diff -Nru twisted-12.0.0/NEWS twisted-12.2.0/NEWS --- twisted-12.0.0/NEWS 2012-02-10 14:56:39.000000000 +0000 +++ twisted-12.2.0/NEWS 2012-08-30 12:51:21.000000000 +0000 @@ -1,6 +1,179 @@ Ticket numbers in this file can be looked up by visiting http://twistedmatrix.com/trac/ticket/ +Twisted Core 12.2.0 (2012-08-26) +================================ + +Features +-------- + - twisted.protocols.sip.MessageParser now handles multiline headers. + (#2198) + - twisted.internet.endpoints now provides StandardIOEndpoint, a + Standard I/O endpoint. (#4697) + - If a FTPCmdError occurs during twisted.protocols.ftp.FTP.ftp_RETR + sending the file (i.e. it is raised by the IReadFile.send method it + invokes), then it will use that to return an error to the client + rather than necessarily sending a 426 CNX_CLOSED_TXFR_ABORTED + error. (#4913) + - twisted.internet.interfaces.IReactorSocket.adoptStreamConnection is + implemented by some reactors as a way to add an existing + established connection to them. (#5570) + - twisted.internet.endpoints now provides TCP6ServerEndpoint, an IPv6 + TCP server endpoint. (#5694) + - twisted.internet.endpoints now provides TCP6ClientEndpoint, an IPv6 + TCP client endpoint. (#5695) + - twisted.internet.endpoints.serverFromString, the endpoint string + description feature, can now be used to create IPv6 TCP servers. + (#5699) + - twisted.internet.endpoints.serverFromString, the endpoint string + description feature, can now be used to create servers that run on + Standard I/O. (#5729) + - twisted.trial.unittest now offers SynchronousTestCase, a test case + base class that provides usability improvements but not reactor- + based testing features. (#5853) + +Bugfixes +-------- + - twisted.internet.Process.signalProcess now catches ESRCH raised by + os.kill call and raises ProcessExitedAlready instead. (#2420) + - TLSMemoryBIOProtocol (and therefore all SSL transports if pyOpenSSL + >= 0.10) now provides the interfaces already provided by the + underlying transport. (#5182) + +Deprecations and Removals +------------------------- + - Python 2.5 is no longer supported. (#5553) + - The --extra option of trial, deprecated since 11.0, is removed now. + (#3374) + - addPluginDir and getPluginDirs in twisted.python.util are + deprecated now. (#4533) + - twisted.trial.runner.DocTestCase, deprecated in Twisted 8.0, has + been removed. (#5554) + - startKeepingErrors, flushErrors, ignoreErrors, and clearIgnores in + twisted.python.log (deprecated since Twisted 2.5) are removed now. + (#5765) + - unzip, unzipIter, and countZipFileEntries in + twisted.python.zipstream (deprecated in Twisted 11.0) are removed + now. (#5766) + - twisted.test.time_helpers, deprecated since Twisted 10.0, has been + removed. (#5820) + +Other +----- + - #4244, #4532, #4930, #4999, #5129, #5138, #5385, #5521, #5655, + #5674, #5679, #5687, #5688, #5689, #5692, #5707, #5734, #5736, + #5745, #5746, #5747, #5749, #5784, #5816, #5817, #5818, #5819, + #5830, #5857, #5858, #5859, #5869, #5632 + + +Twisted Core 12.1.0 (2012-06-02) +================================ + +Features +-------- + - The kqueue reactor has been revived. (#1918) + - twisted.python.filepath now provides IFilePath, an interface for + file path objects. (#2176) + - New gtk3 and gobject-introspection reactors have been added. + (#4558) + - gtk and glib reactors now run I/O and scheduled events with lower + priority, to ensure the UI stays responsive. (#5067) + - IReactorTCP.connectTCP() can now accept IPv6 address literals + (although not hostnames) in order to support connecting to IPv6 + hosts. (#5085) + - twisted.internet.interfaces.IReactorSocket, a new interface, is now + supported by some reactors to listen on sockets set up by external + software (eg systemd or launchd). (#5248) + - twisted.internet.endpoints.clientFromString now also supports + strings in the form of tcp:example.com:80 and ssl:example.com:4321 + (#5358) + - twisted.python.constants.Flags now provides a way to define + collections of flags for bitvector-type uses. (#5384) + - The epoll(7)-based reactor is now the default reactor on Linux. + (#5478) + - twisted.python.runtime.platform.isLinux can be used to check if + Twisted is running on Linux. (#5491) + - twisted.internet.endpoints.serverFromString now recognizes a + "systemd" endpoint type, for listening on a server port inherited + from systemd. (#5575) + - Connections created using twisted.internet.interfaces.IReactorUNIX + now support sending and receiving file descriptors between + different processes. (#5615) + - twisted.internet.endpoints.clientFromString now supports UNIX + client endpoint strings with the path argument specified like + "unix:/foo/bar" in addition to the old style, "unix:path=/foo/bar". + (#5640) + - twisted.protocols.amp.Descriptor is a new AMP argument type which + supports passing file descriptors as AMP command arguments over + UNIX connections. (#5650) + +Bugfixes +-------- + - twisted.internet.abstract.FileDescriptor implements + twisted.internet.interfaces.IPushProducer instead of + twisted.internet.interfaces.IProducer. + twisted.internet.iocpreactor.abstract.FileHandle implements + twisted.internet.interfaces.IPushProducer instead of + twisted.internet.interfaces.IProducer. (#4386) + - The epoll reactor now supports reading/writing to regular files on + stdin/stdout. (#4429) + - Calling .cancel() on any Twisted-provided client endpoint + (TCP4ClientEndpoint, UNIXClientEndpoint, SSL4ClientEndpoint) now + works as documented, rather than logging an AlreadyCalledError. + (#4710) + - A leak of OVERLAPPED structures in some IOCP error cases has been + fixed. (#5372) + - twisted.internet._pollingfile._PollableWritePipe now checks for + outgoing unicode data in write() and writeSequence() instead of + checkWork(). (#5412) + +Improved Documentation +---------------------- + - "Working from Twisted's Subversion repository" links to UQDS and + Combinator are now updated. (#5545) + - Added tkinterdemo.py, an example of Tkinter integration. (#5631) + +Deprecations and Removals +------------------------- + - The 'unsigned' flag to twisted.scripts.tap2rpm.MyOptions is now + deprecated. (#4086) + - Removed the unreachable _fileUrandom method from + twisted.python.randbytes.RandomFactory. (#4530) + - twisted.persisted.journal is removed, deprecated since Twisted + 11.0. (#4805) + - Support for pyOpenSSL 0.9 and older is now deprecated. pyOpenSSL + 0.10 or newer will soon be required in order to use Twisted's SSL + features. (#4974) + - backwardsCompatImplements and fixClassImplements are removed from + twisted.python.components, deprecated in 2006. (#5034) + - twisted.python.reflect.macro was removed, deprecated since Twisted + 8.2. (#5035) + - twisted.python.text.docstringLStrip, deprecated since Twisted + 10.2.0, has been removed (#5036) + - Removed the deprecated dispatch and dispatchWithCallback methods + from twisted.python.threadpool.ThreadPool (deprecated since 8.0) + (#5037) + - twisted.scripts.tapconvert is now deprecated. (#5038) + - twisted.python.reflect's Settable, AccessorType, PropertyAccessor, + Accessor, OriginalAccessor and Summer are now deprecated. (#5451) + - twisted.python.threadpool.ThreadSafeList (deprecated in 10.1) is + removed. (#5473) + - twisted.application.app.initialLog, deprecated since Twisted 8.2.0, + has been removed. (#5480) + - twisted.spread.refpath was deleted, deprecated since Twisted 9.0. + (#5482) + - twisted.python.otp, deprecated since 9.0, is removed. (#5493) + - Removed `dsu`, `moduleMovedForSplit`, and `dict` from + twisted.python.util (deprecated since 10.2) (#5516) + +Other +----- + - #2723, #3114, #3398, #4388, #4489, #5055, #5116, #5242, #5380, + #5392, #5447, #5457, #5484, #5489, #5492, #5494, #5512, #5523, + #5558, #5572, #5583, #5593, #5620, #5621, #5623, #5625, #5637, + #5652, #5653, #5656, #5657, #5660, #5673 + + Twisted Core 12.0.0 (2012-02-10) ================================ @@ -948,7 +1121,7 @@ Fixes ----- - TLS Session Tickets are now disabled by default, allowing connections to - certain servers which hang when an empty session ticket is received (like + certain servers which hang when an empty session ticket is received (like GTalk) (#3463) - twisted.enterprise.adbapi.ConnectionPool's noisy attribute now defaults to False, as documented (#1806) @@ -1402,7 +1575,7 @@ Fixes ----- - - Many trial fixes, as usual + - Many trial fixes, as usual - All API documentation is now correctly formatted as epytext (#1545) - twisted.python.filepath.FilePath.__repr__ is safer. - Fix trial's "until-failure" mode. (#1453) @@ -1493,7 +1666,7 @@ ----- - FTP client and server improvements - Trial improvements: The code is now much simpler, and more stable. - - twisted.protocols.basic.FileSender now works with empty files + - twisted.protocols.basic.FileSender now works with empty files - Twisted should now be much more usable on Pythons without thread support. - minor improvements to process code in win32eventreactor - twistd -y (--python) now implies -o (--nosave). [539] @@ -1574,7 +1747,7 @@ - More correct daemonization in twistd. - twisted.python.log: do not close the log because of invalid format string. - - Disabled automatic import of cBanana. + - Disabled automatic import of cBanana. - Boolean support for twisted.persisted.marmalade. - Refactor of plugin and application HOWTO documentation - Async HOWTO expanded greatly. diff -Nru twisted-12.0.0/README twisted-12.2.0/README --- twisted-12.0.0/README 2012-02-10 14:56:39.000000000 +0000 +++ twisted-12.2.0/README 2012-08-26 12:13:01.000000000 +0000 @@ -1,4 +1,4 @@ -Twisted Core 12.0.0 +Twisted Core 12.2.0 =================== Twisted Core makes up the core parts of Twisted, including: diff -Nru twisted-12.0.0/debian/changelog twisted-12.2.0/debian/changelog --- twisted-12.0.0/debian/changelog 2012-05-15 19:29:33.000000000 +0000 +++ twisted-12.2.0/debian/changelog 2012-09-11 11:12:57.000000000 +0000 @@ -1,11 +1,11 @@ -twisted (12.0.0-1ubuntu1) quantal; urgency=low +twisted (12.2.0-1) experimental; urgency=low - * Merge from Debian. Remaining Ubuntu changes: - - debian/patches/00_gi_gtk3reactor.patch: Backport - gireactor/gtk3reactor and gtk2reactor refactor from svn - (LP: #571648, LP: #851187) + * New upstream version + * Drop the _epoll.so C extension, as Twisted now supports only + Python >= 2.6 and there's stdlib support for epoll since 2.6 + * Add sendmsg.so C extension to python-twisted-bin - -- Barry Warsaw Tue, 15 May 2012 15:29:23 -0400 + -- Free Ekanayaka Tue, 11 Sep 2012 10:06:25 +0200 twisted (12.0.0-1) sid; urgency=low @@ -15,21 +15,6 @@ -- Free Ekanayaka Tue, 17 Apr 2012 15:36:37 +0200 -twisted (11.1.0-1ubuntu2) precise; urgency=low - - * debian/patches/01_posix_wakeups.patch: - - Backport wakeup change from trunk gtk2refactoring (LP: #935756) - - -- Rodney Dawes Thu, 08 Mar 2012 11:25:48 -0500 - -twisted (11.1.0-1ubuntu1) precise; urgency=low - - * debian/patches/00_gi_gtk3reactor.patch: - - Backport gireactor/gtk3reactor and gtk2reactor refactor from svn - (LP: #571648, LP: #851187) - - -- Rodney Dawes Wed, 15 Feb 2012 21:39:07 -0500 - twisted (11.1.0-1) unstable; urgency=low * New upstream version. diff -Nru twisted-12.0.0/debian/control twisted-12.2.0/debian/control --- twisted-12.0.0/debian/control 2012-05-15 15:18:51.000000000 +0000 +++ twisted-12.2.0/debian/control 2012-09-11 11:12:57.000000000 +0000 @@ -1,8 +1,7 @@ Source: twisted Section: python Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Matthias Klose +Maintainer: Matthias Klose Uploaders: Free Ekanayaka Build-Depends: debhelper (>=7.0.50~), python-all-dev (>= 2.6.6-3~), python-all-dbg, python-zope.interface-dbg, patch Build-Conflicts: python-setuptools @@ -64,7 +63,7 @@ Package: python-twisted Architecture: all Priority: extra -Depends: ${python:Depends}, python-twisted-core (>= 12.0), python-twisted-conch (>= 1:12.0), python-twisted-mail (>= 12.0), python-twisted-lore (>= 12.0), python-twisted-names (>= 12.0), python-twisted-news (>= 12.0), python-twisted-runner (>= 12.0), python-twisted-web (>= 12.0), python-twisted-words (>= 12.0), ${misc:Depends} +Depends: ${python:Depends}, python-twisted-core (>= 12.2), python-twisted-conch (>= 1:12.2), python-twisted-mail (>= 12.2), python-twisted-lore (>= 12.2), python-twisted-names (>= 12.2), python-twisted-news (>= 12.2), python-twisted-runner (>= 12.2), python-twisted-web (>= 12.2), python-twisted-words (>= 12.2), ${misc:Depends} Provides: ${python:Provides} Description: Event-based framework for internet applications (dependency package) This is a dependency package that depends on the twisted core library and diff -Nru twisted-12.0.0/debian/patches/00_gi_gtk3reactor.patch twisted-12.2.0/debian/patches/00_gi_gtk3reactor.patch --- twisted-12.0.0/debian/patches/00_gi_gtk3reactor.patch 2012-05-15 19:22:13.000000000 +0000 +++ twisted-12.2.0/debian/patches/00_gi_gtk3reactor.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,1017 +0,0 @@ -=== added file 'twisted/internet/_glibbase.py' ---- /dev/null -+++ b/twisted/internet/_glibbase.py -@@ -0,0 +1,368 @@ -+# -*- test-case-name: twisted.internet.test -*- -+# Copyright (c) Twisted Matrix Laboratories. -+# See LICENSE for details. -+ -+""" -+This module provides base support for Twisted to interact with the glib/gtk -+mainloops. -+ -+The classes in this module should not be used directly, but rather you should -+import gireactor or gtk3reactor for GObject Introspection based applications, -+or glib2reactor or gtk2reactor for applications using legacy static bindings. -+""" -+ -+import signal -+ -+from twisted.internet import base, posixbase, selectreactor -+from twisted.internet.interfaces import IReactorFDSet -+from twisted.python import log, runtime -+from twisted.python.compat import set -+from zope.interface import implements -+ -+ -+class GlibSignalMixin(object): -+ -+ if runtime.platformType == 'posix': -+ -+ def _handleSignals(self): -+ # Let the base class do its thing, but pygtk is probably -+ # going to stomp on us so go beyond that and set up some -+ # signal handling which pygtk won't mess with. This would -+ # be better done by letting this reactor select a -+ # different implementation of installHandler for -+ # _SIGCHLDWaker to use. Then, at least, we could fall -+ # back to our extension module. See #4286. -+ from twisted.internet.process import ( -+ reapAllProcesses as _reapAllProcesses) -+ base._SignalReactorMixin._handleSignals(self) -+ signal.signal(signal.SIGCHLD, -+ lambda *a: self.callFromThread(_reapAllProcesses)) -+ if getattr(signal, "siginterrupt", None) is not None: -+ signal.siginterrupt(signal.SIGCHLD, False) -+ # Like the base, reap processes now in case a process -+ # exited before the handlers above were installed. -+ _reapAllProcesses() -+ -+ -+ -+class GlibWaker(posixbase._UnixWaker): -+ """ -+ Run scheduled events after waking up. -+ """ -+ -+ def doRead(self): -+ posixbase._UnixWaker.doRead(self) -+ self.reactor._simulate() -+ -+ -+ -+class GlibReactorBase(GlibSignalMixin, -+ posixbase.PosixReactorBase, posixbase._PollLikeMixin): -+ """ -+ Base class for GObject event loop reactors. -+ -+ Notification for I/O events (reads and writes on file descriptors) is done -+ by the the gobject-based event loop. File descriptors are registered with -+ gobject with the appropriate flags for read/write/disconnect notification. -+ -+ Time-based events, the results of C{callLater} and C{callFromThread}, are -+ handled differently. Rather than registering each event with gobject, a -+ single gobject timeout is registered for the earliest scheduled event, the -+ output of C{reactor.timeout()}. For example, if there are timeouts in 1, 2 -+ and 3.4 seconds, a single timeout is registered for 1 second in the -+ future. When this timeout is hit, C{_simulate} is called, which calls the -+ appropriate Twisted-level handlers, and a new timeout is added to gobject -+ by the C{_reschedule} method. -+ -+ To handle C{callFromThread} events, we use a custom waker that calls -+ C{_simulate} whenever it wakes up. -+ -+ @ivar _sources: A dictionary mapping L{FileDescriptor} instances to -+ GSource handles. -+ -+ @ivar _reads: A set of L{FileDescriptor} instances currently monitored for -+ reading. -+ -+ @ivar _writes: A set of L{FileDescriptor} instances currently monitored for -+ writing. -+ -+ @ivar _simtag: A GSource handle for the next L{simulate} call. -+ """ -+ implements(IReactorFDSet) -+ -+ # Install a waker that knows it needs to call C{_simulate} in order to run -+ # callbacks queued from a thread: -+ _wakerFactory = GlibWaker -+ -+ def __init__(self, glib_module, gtk_module, useGtk=False): -+ self._simtag = None -+ self._reads = set() -+ self._writes = set() -+ self._sources = {} -+ self._glib = glib_module -+ self._gtk = gtk_module -+ posixbase.PosixReactorBase.__init__(self) -+ -+ self._source_remove = self._glib.source_remove -+ self._timeout_add = self._glib.timeout_add -+ -+ def _mainquit(): -+ if self._gtk.main_level(): -+ self._gtk.main_quit() -+ -+ if useGtk: -+ self._pending = self._gtk.events_pending -+ self._iteration = self._gtk.main_iteration_do -+ self._crash = _mainquit -+ self._run = self._gtk.main -+ else: -+ self.context = self._glib.main_context_default() -+ self._pending = self.context.pending -+ self._iteration = self.context.iteration -+ self.loop = self._glib.MainLoop() -+ self._crash = lambda: self._glib.idle_add(self.loop.quit) -+ self._run = self.loop.run -+ -+ -+ # The input_add function in pygtk1 checks for objects with a -+ # 'fileno' method and, if present, uses the result of that method -+ # as the input source. The pygtk2 input_add does not do this. The -+ # function below replicates the pygtk1 functionality. -+ -+ # In addition, pygtk maps gtk.input_add to _gobject.io_add_watch, and -+ # g_io_add_watch() takes different condition bitfields than -+ # gtk_input_add(). We use g_io_add_watch() here in case pygtk fixes this -+ # bug. -+ def input_add(self, source, condition, callback): -+ if hasattr(source, 'fileno'): -+ # handle python objects -+ def wrapper(source, condition, real_s=source, real_cb=callback): -+ return real_cb(real_s, condition) -+ return self._glib.io_add_watch(source.fileno(), condition, wrapper) -+ else: -+ return self._glib.io_add_watch(source, condition, callback) -+ -+ -+ def _ioEventCallback(self, source, condition): -+ """ -+ Called by event loop when an I/O event occurs. -+ """ -+ log.callWithLogger( -+ source, self._doReadOrWrite, source, source, condition) -+ return True # True = don't auto-remove the source -+ -+ -+ def _add(self, source, primary, other, primaryFlag, otherFlag): -+ """ -+ Add the given L{FileDescriptor} for monitoring either for reading or -+ writing. If the file is already monitored for the other operation, we -+ delete the previous registration and re-register it for both reading -+ and writing. -+ """ -+ if source in primary: -+ return -+ flags = primaryFlag -+ if source in other: -+ self._source_remove(self._sources[source]) -+ flags |= otherFlag -+ self._sources[source] = self.input_add( -+ source, flags, self._ioEventCallback) -+ primary.add(source) -+ -+ -+ def addReader(self, reader): -+ """ -+ Add a L{FileDescriptor} for monitoring of data available to read. -+ """ -+ self._add(reader, self._reads, self._writes, -+ self.INFLAGS, self.OUTFLAGS) -+ -+ -+ def addWriter(self, writer): -+ """ -+ Add a L{FileDescriptor} for monitoring ability to write data. -+ """ -+ self._add(writer, self._writes, self._reads, -+ self.OUTFLAGS, self.INFLAGS) -+ -+ -+ def getReaders(self): -+ """ -+ Retrieve the list of current L{FileDescriptor} monitored for reading. -+ """ -+ return list(self._reads) -+ -+ -+ def getWriters(self): -+ """ -+ Retrieve the list of current L{FileDescriptor} monitored for writing. -+ """ -+ return list(self._writes) -+ -+ -+ def removeAll(self): -+ """ -+ Remove monitoring for all registered L{FileDescriptor}s. -+ """ -+ return self._removeAll(self._reads, self._writes) -+ -+ -+ def _remove(self, source, primary, other, flags): -+ """ -+ Remove monitoring the given L{FileDescriptor} for either reading or -+ writing. If it's still monitored for the other operation, we -+ re-register the L{FileDescriptor} for only that operation. -+ """ -+ if source not in primary: -+ return -+ self._source_remove(self._sources[source]) -+ primary.remove(source) -+ if source in other: -+ self._sources[source] = self.input_add( -+ source, flags, self._ioEventCallback) -+ else: -+ self._sources.pop(source) -+ -+ -+ def removeReader(self, reader): -+ """ -+ Stop monitoring the given L{FileDescriptor} for reading. -+ """ -+ self._remove(reader, self._reads, self._writes, self.OUTFLAGS) -+ -+ -+ def removeWriter(self, writer): -+ """ -+ Stop monitoring the given L{FileDescriptor} for writing. -+ """ -+ self._remove(writer, self._writes, self._reads, self.INFLAGS) -+ -+ -+ def iterate(self, delay=0): -+ """ -+ One iteration of the event loop, for trial's use. -+ -+ This is not used for actual reactor runs. -+ """ -+ self.runUntilCurrent() -+ while self._pending(): -+ self._iteration(0) -+ -+ -+ def crash(self): -+ """ -+ Crash the reactor. -+ """ -+ posixbase.PosixReactorBase.crash(self) -+ self._crash() -+ -+ -+ def stop(self): -+ """ -+ Stop the reactor. -+ """ -+ posixbase.PosixReactorBase.stop(self) -+ # The base implementation only sets a flag, to ensure shutting down is -+ # not reentrant. Unfortunately, this flag is not meaningful to the -+ # gobject event loop. We therefore call wakeUp() to ensure the event -+ # loop will call back into Twisted once this iteration is done. This -+ # will result in self.runUntilCurrent() being called, where the stop -+ # flag will trigger the actual shutdown process, eventually calling -+ # crash() which will do the actual gobject event loop shutdown. -+ self.wakeUp() -+ -+ -+ def run(self, installSignalHandlers=True): -+ """ -+ Run the reactor. -+ """ -+ self.callWhenRunning(self._reschedule) -+ self.startRunning(installSignalHandlers=installSignalHandlers) -+ if self._started: -+ self._run() -+ -+ -+ def callLater(self, *args, **kwargs): -+ """ -+ Schedule a C{DelayedCall}. -+ """ -+ result = posixbase.PosixReactorBase.callLater(self, *args, **kwargs) -+ # Make sure we'll get woken up at correct time to handle this new -+ # scheduled call: -+ self._reschedule() -+ return result -+ -+ -+ def _reschedule(self): -+ """ -+ Schedule a glib timeout for C{_simulate}. -+ """ -+ if self._simtag is not None: -+ self._source_remove(self._simtag) -+ self._simtag = None -+ timeout = self.timeout() -+ if timeout is not None: -+ self._simtag = self._timeout_add(int(timeout * 1000), -+ self._simulate) -+ -+ -+ def _simulate(self): -+ """ -+ Run timers, and then reschedule glib timeout for next scheduled event. -+ """ -+ self.runUntilCurrent() -+ self._reschedule() -+ -+ -+ -+class PortableGlibReactorBase(GlibSignalMixin, selectreactor.SelectReactor): -+ """ -+ Base class for GObject event loop reactors that works on Windows. -+ -+ Sockets aren't supported by GObject's input_add on Win32. -+ """ -+ def __init__(self, glib_module, gtk_module, useGtk=False): -+ self._simtag = None -+ self._glib = glib_module -+ self._gtk = gtk_module -+ selectreactor.SelectReactor.__init__(self) -+ -+ self._source_remove = self._glib.source_remove -+ self._timeout_add = self._glib.timeout_add -+ -+ def _mainquit(): -+ if self._gtk.main_level(): -+ self._gtk.main_quit() -+ -+ if useGtk: -+ self._crash = _mainquit -+ self._run = self._gtk.main -+ else: -+ self.loop = self._glib.MainLoop() -+ self._crash = lambda: self._glib.idle_add(self.loop.quit) -+ self._run = self.loop.run -+ -+ -+ def crash(self): -+ selectreactor.SelectReactor.crash(self) -+ self._crash() -+ -+ -+ def run(self, installSignalHandlers=True): -+ self.startRunning(installSignalHandlers=installSignalHandlers) -+ self._timeout_add(0, self.simulate) -+ if self._started: -+ self._run() -+ -+ -+ def simulate(self): -+ """ -+ Run simulation loops and reschedule callbacks. -+ """ -+ if self._simtag is not None: -+ self._source_remove(self._simtag) -+ self.iterate() -+ timeout = min(self.timeout(), 0.01) -+ if timeout is None: -+ timeout = 0.01 -+ self._simtag = self._timeout_add(int(timeout * 1000), self.simulate) ---- /dev/null -+++ b/twisted/internet/gireactor.py -@@ -0,0 +1,93 @@ -+# Copyright (c) Twisted Matrix Laboratories. -+# See LICENSE for details. -+ -+""" -+This module provides support for Twisted to interact with the glib -+mainloop via GObject Introspection. -+ -+In order to use this support, simply do the following:: -+ -+ from twisted.internet import gireactor -+ gireactor.install() -+ -+Then use twisted.internet APIs as usual. The other methods here are not -+intended to be called directly. -+""" -+ -+import sys -+ -+if 'gobject' in sys.modules: -+ raise ImportError( -+ "Introspected and static glib/gtk bindings must not be mixed; can't " -+ "import gireactor since pygtk2 module is already imported.") -+ -+from gi.repository import GLib -+GLib.threads_init() -+ -+from twisted.internet import _glibbase -+from twisted.python import runtime -+ -+# We need to override sys.modules with these to prevent imports. -+# This is required, as importing these can result in SEGFAULTs. -+sys.modules['glib'] = None -+sys.modules['gobject'] = None -+sys.modules['gio'] = None -+sys.modules['gtk'] = None -+ -+ -+ -+class GIReactor(_glibbase.GlibReactorBase): -+ """ -+ GObject-introspection event loop reactor. -+ """ -+ _POLL_DISCONNECTED = (GLib.IOCondition.HUP | GLib.IOCondition.ERR | -+ GLib.IOCondition.NVAL) -+ _POLL_IN = GLib.IOCondition.IN -+ _POLL_OUT = GLib.IOCondition.OUT -+ -+ # glib's iochannel sources won't tell us about any events that we haven't -+ # asked for, even if those events aren't sensible inputs to the poll() -+ # call. -+ INFLAGS = _POLL_IN | _POLL_DISCONNECTED -+ OUTFLAGS = _POLL_OUT | _POLL_DISCONNECTED -+ -+ def __init__(self, useGtk=False): -+ _gtk = None -+ if useGtk is True: -+ from gi.repository import Gtk as _gtk -+ -+ _glibbase.GlibReactorBase.__init__(self, GLib, _gtk, useGtk=useGtk) -+ -+ -+ -+class PortableGIReactor(_glibbase.PortableGlibReactorBase): -+ """ -+ Portable GObject Introspection event loop reactor. -+ """ -+ def __init__(self, useGtk=False): -+ _gtk = None -+ if useGtk is True: -+ from gi.repository import Gtk as _gtk -+ -+ _glibbase.PortableGlibReactorBase.__init__(self, GLib, _gtk, -+ useGtk=useGtk) -+ -+ -+def install(useGtk=False): -+ """ -+ Configure the twisted mainloop to be run inside the glib mainloop. -+ -+ @param useGtk: should GTK+ rather than glib event loop be -+ used (this will be slightly slower but does support GUI). -+ """ -+ if runtime.platform.getType() == 'posix': -+ reactor = GIReactor(useGtk=useGtk) -+ else: -+ reactor = PortableGIReactor(useGtk=useGtk) -+ -+ from twisted.internet.main import installReactor -+ installReactor(reactor) -+ return reactor -+ -+ -+__all__ = ['install'] ---- a/twisted/internet/gtk2reactor.py -+++ b/twisted/internet/gtk2reactor.py -@@ -9,21 +9,23 @@ - - In order to use this support, simply do the following:: - -- | from twisted.internet import gtk2reactor -- | gtk2reactor.install() -+ from twisted.internet import gtk2reactor -+ gtk2reactor.install() - - Then use twisted.internet APIs as usual. The other methods here are not - intended to be called directly. -- --When installing the reactor, you can choose whether to use the glib --event loop or the GTK+ event loop which is based on it but adds GUI --integration. - """ - - # System Imports --import sys, signal -+import sys -+ -+if 'gi' in sys.modules: -+ raise ImportError( -+ "Introspected and static glib/gtk bindings must not be mixed; can't " -+ "import gtk2reactor since gi module is already imported.") - --from zope.interface import implements -+# Disable gi imports to avoid potential problems. -+sys.modules['gi'] = None - - try: - if not hasattr(sys, 'frozen'): -@@ -32,6 +34,7 @@ - pygtk.require('2.0') - except (ImportError, AttributeError): - pass # maybe we're using pygtk before this hack existed. -+ - import gobject - if hasattr(gobject, "threads_init"): - # recent versions of python-gtk expose this. python-gtk=2.4.1 -@@ -40,52 +43,8 @@ - gobject.threads_init() - - # Twisted Imports --from twisted.python import log, runtime --from twisted.python.compat import set --from twisted.internet.interfaces import IReactorFDSet --from twisted.internet import base, posixbase, selectreactor -- --POLL_DISCONNECTED = gobject.IO_HUP | gobject.IO_ERR | gobject.IO_NVAL -- --# glib's iochannel sources won't tell us about any events that we haven't --# asked for, even if those events aren't sensible inputs to the poll() --# call. --INFLAGS = gobject.IO_IN | POLL_DISCONNECTED --OUTFLAGS = gobject.IO_OUT | POLL_DISCONNECTED -- -- -- --def _our_mainquit(): -- # XXX: gtk.main_quit() (which is used for crash()) raises an exception if -- # gtk.main_level() == 0; however, all the tests freeze if we use this -- # function to stop the reactor. what gives? (I believe this may have been -- # a stupid mistake where I forgot to import gtk here... I will remove this -- # comment if the tests pass) -- import gtk -- if gtk.main_level(): -- gtk.main_quit() -- -- -- --class _Gtk2SignalMixin(object): -- if runtime.platformType == 'posix': -- def _handleSignals(self): -- # Let the base class do its thing, but pygtk is probably -- # going to stomp on us so go beyond that and set up some -- # signal handling which pygtk won't mess with. This would -- # be better done by letting this reactor select a -- # different implementation of installHandler for -- # _SIGCHLDWaker to use. Then, at least, we could fall -- # back to our extension module. See #4286. -- from twisted.internet.process import reapAllProcesses as _reapAllProcesses -- base._SignalReactorMixin._handleSignals(self) -- signal.signal(signal.SIGCHLD, lambda *a: self.callFromThread(_reapAllProcesses)) -- if getattr(signal, "siginterrupt", None) is not None: -- signal.siginterrupt(signal.SIGCHLD, False) -- # Like the base, reap processes now in case a process -- # exited before the handlers above were installed. -- _reapAllProcesses() -- -+from twisted.internet import _glibbase, posixbase -+from twisted.python import runtime - - - class _Gtk2Waker(posixbase._UnixWaker): -@@ -99,40 +58,11 @@ - - - --class Gtk2Reactor(_Gtk2SignalMixin, posixbase.PosixReactorBase, posixbase._PollLikeMixin): -+class Gtk2Reactor(_glibbase.GlibReactorBase): - """ -- GTK+-2 event loop reactor. -- -- Notification for I/O events (reads and writes on file descriptors) is done -- by the the gobject-based event loop. File descriptors are registered with -- gobject with the appropriate flags for read/write/disconnect notification. -- -- Time-based events, the results of C{callLater} and C{callFromThread}, are -- handled differently. Rather than registering each event with gobject, a -- single gobject timeout is registered for the earliest scheduled event, the -- output of C{reactor.timeout()}. For example, if there are timeouts in 1, 2 -- and 3.4 seconds, a single timeout is registered for 1 second in the -- future. When this timeout is hit, C{_simulate} is called, which calls the -- appropriate Twisted-level handlers, and a new timeout is added to gobject -- by the C{_reschedule} method. -- -- To handle C{callFromThread} events, we use a custom waker that calls -- C{_simulate} whenever it wakes up. -- -- @ivar _sources: A dictionary mapping L{FileDescriptor} instances to gtk -- watch handles. -- -- @ivar _reads: A set of L{FileDescriptor} instances currently monitored for -- reading. -- -- @ivar _writes: A set of L{FileDescriptor} instances currently monitored for -- writing. -- -- @ivar _simtag: A gtk timeout handle for the next L{_simulate} call. -+ PyGTK+ 2 event loop reactor. - """ -- implements(IReactorFDSet) -- -- _POLL_DISCONNECTED = POLL_DISCONNECTED -+ _POLL_DISCONNECTED = gobject.IO_HUP | gobject.IO_ERR | gobject.IO_NVAL - _POLL_IN = gobject.IO_IN - _POLL_OUT = gobject.IO_OUT - -@@ -140,262 +70,34 @@ - # callbacks queued from a thread: - _wakerFactory = _Gtk2Waker - -+ # glib's iochannel sources won't tell us about any events that we haven't -+ # asked for, even if those events aren't sensible inputs to the poll() -+ # call. -+ INFLAGS = _POLL_IN | _POLL_DISCONNECTED -+ OUTFLAGS = _POLL_OUT | _POLL_DISCONNECTED -+ - def __init__(self, useGtk=True): -- self._simtag = None -- self._reads = set() -- self._writes = set() -- self._sources = {} -- posixbase.PosixReactorBase.__init__(self) -- # pre 2.3.91 the glib iteration and mainloop functions didn't release -- # global interpreter lock, thus breaking thread and signal support. -- if getattr(gobject, "pygtk_version", ()) >= (2, 3, 91) and not useGtk: -- self.context = gobject.main_context_default() -- self.__pending = self.context.pending -- self.__iteration = self.context.iteration -- self.loop = gobject.MainLoop() -- self.__crash = self.loop.quit -- self.__run = self.loop.run -- else: -- import gtk -- self.__pending = gtk.events_pending -- self.__iteration = gtk.main_iteration -- self.__crash = _our_mainquit -- self.__run = gtk.main -- -- -- # The input_add function in pygtk1 checks for objects with a -- # 'fileno' method and, if present, uses the result of that method -- # as the input source. The pygtk2 input_add does not do this. The -- # function below replicates the pygtk1 functionality. -- -- # In addition, pygtk maps gtk.input_add to _gobject.io_add_watch, and -- # g_io_add_watch() takes different condition bitfields than -- # gtk_input_add(). We use g_io_add_watch() here in case pygtk fixes this -- # bug. -- def input_add(self, source, condition, callback): -- if hasattr(source, 'fileno'): -- # handle python objects -- def wrapper(source, condition, real_s=source, real_cb=callback): -- return real_cb(real_s, condition) -- return gobject.io_add_watch(source.fileno(), condition, wrapper) -- else: -- return gobject.io_add_watch(source, condition, callback) -- -- -- def _ioEventCallback(self, source, condition): -- """ -- Called by event loop when an I/O event occurs. -- """ -- log.callWithLogger( -- source, self._doReadOrWrite, source, source, condition) -- return 1 # 1=don't auto-remove the source -- -- -- def _add(self, source, primary, other, primaryFlag, otherFlag): -- """ -- Add the given L{FileDescriptor} for monitoring either for reading or -- writing. If the file is already monitored for the other operation, we -- delete the previous registration and re-register it for both reading -- and writing. -- """ -- if source in primary: -- return -- flags = primaryFlag -- if source in other: -- gobject.source_remove(self._sources[source]) -- flags |= otherFlag -- self._sources[source] = self.input_add( -- source, flags, self._ioEventCallback) -- primary.add(source) -- -- -- def addReader(self, reader): -- """ -- Add a L{FileDescriptor} for monitoring of data available to read. -- """ -- self._add(reader, self._reads, self._writes, INFLAGS, OUTFLAGS) -- -- -- def addWriter(self, writer): -- """ -- Add a L{FileDescriptor} for monitoring ability to write data. -- """ -- self._add(writer, self._writes, self._reads, OUTFLAGS, INFLAGS) -- -- -- def getReaders(self): -- """ -- Retrieve the list of current L{FileDescriptor} monitored for reading. -- """ -- return list(self._reads) -- -- -- def getWriters(self): -- """ -- Retrieve the list of current L{FileDescriptor} monitored for writing. -- """ -- return list(self._writes) -- -- -- def removeAll(self): -- """ -- Remove monitoring for all registered L{FileDescriptor}s. -- """ -- return self._removeAll(self._reads, self._writes) -- -- -- def _remove(self, source, primary, other, flags): -- """ -- Remove monitoring the given L{FileDescriptor} for either reading or -- writing. If it's still monitored for the other operation, we -- re-register the L{FileDescriptor} for only that operation. -- """ -- if source not in primary: -- return -- gobject.source_remove(self._sources[source]) -- primary.remove(source) -- if source in other: -- self._sources[source] = self.input_add( -- source, flags, self._ioEventCallback) -- else: -- self._sources.pop(source) -- -- -- def removeReader(self, reader): -- """ -- Stop monitoring the given L{FileDescriptor} for reading. -- """ -- self._remove(reader, self._reads, self._writes, OUTFLAGS) -- -- -- def removeWriter(self, writer): -- """ -- Stop monitoring the given L{FileDescriptor} for writing. -- """ -- self._remove(writer, self._writes, self._reads, INFLAGS) -- -- -- def iterate(self, delay=0): -- """ -- One iteration of the event loop, for trial's use. -- -- This is not used for actual reactor runs. -- """ -- self.runUntilCurrent() -- while self.__pending(): -- self.__iteration(0) -- -- -- def crash(self): -- """ -- Crash the reactor. -- """ -- posixbase.PosixReactorBase.crash(self) -- self.__crash() -- -- -- def stop(self): -- """ -- Stop the reactor. -- """ -- posixbase.PosixReactorBase.stop(self) -- # The base implementation only sets a flag, to ensure shutting down is -- # not reentrant. Unfortunately, this flag is not meaningful to the -- # gobject event loop. We therefore call wakeUp() to ensure the event -- # loop will call back into Twisted once this iteration is done. This -- # will result in self.runUntilCurrent() being called, where the stop -- # flag will trigger the actual shutdown process, eventually calling -- # crash() which will do the actual gobject event loop shutdown. -- self.wakeUp() -- -- -- def run(self, installSignalHandlers=1): -- """ -- Run the reactor. -- """ -- self.callWhenRunning(self._reschedule) -- self.startRunning(installSignalHandlers=installSignalHandlers) -- if self._started: -- self.__run() -- -- -- def callLater(self, *args, **kwargs): -- """ -- Schedule a C{DelayedCall}. -- """ -- result = posixbase.PosixReactorBase.callLater(self, *args, **kwargs) -- # Make sure we'll get woken up at correct time to handle this new -- # scheduled call: -- self._reschedule() -- return result -- -- -- def _reschedule(self): -- """ -- Schedule a glib timeout for C{_simulate}. -- """ -- if self._simtag is not None: -- gobject.source_remove(self._simtag) -- self._simtag = None -- timeout = self.timeout() -- if timeout is not None: -- self._simtag = gobject.timeout_add(int(timeout * 1000), -- self._simulate) -- -- -- def _simulate(self): -- """ -- Run timers, and then reschedule glib timeout for next scheduled event. -- """ -- self.runUntilCurrent() -- self._reschedule() -+ _gtk = None -+ if useGtk is True: -+ import gtk as _gtk -+ -+ _glibbase.GlibReactorBase.__init__(self, gobject, _gtk, useGtk=useGtk) - - - --class PortableGtkReactor(_Gtk2SignalMixin, selectreactor.SelectReactor): -+class PortableGtkReactor(_glibbase.PortableGlibReactorBase): - """ - Reactor that works on Windows. - - Sockets aren't supported by GTK+'s input_add on Win32. - """ -- _simtag = None -- -- def crash(self): -- selectreactor.SelectReactor.crash(self) -- import gtk -- # mainquit is deprecated in newer versions -- if gtk.main_level(): -- if hasattr(gtk, 'main_quit'): -- gtk.main_quit() -- else: -- gtk.mainquit() -- -- -- def run(self, installSignalHandlers=1): -- import gtk -- self.startRunning(installSignalHandlers=installSignalHandlers) -- gobject.timeout_add(0, self.simulate) -- # mainloop is deprecated in newer versions -- if self._started: -- if hasattr(gtk, 'main'): -- gtk.main() -- else: -- gtk.mainloop() -- -- -- def simulate(self): -- """ -- Run simulation loops and reschedule callbacks. -- """ -- if self._simtag is not None: -- gobject.source_remove(self._simtag) -- self.iterate() -- timeout = min(self.timeout(), 0.01) -- if timeout is None: -- timeout = 0.01 -- # grumble -- self._simtag = gobject.timeout_add(int(timeout * 1010), self.simulate) -+ def __init__(self, useGtk=True): -+ _gtk = None -+ if useGtk is True: -+ import gtk as _gtk - -+ _glibbase.PortableGlibReactorBase.__init__(self, gobject, _gtk, -+ useGtk=useGtk) - - - def install(useGtk=True): -@@ -411,7 +113,6 @@ - return reactor - - -- - def portableInstall(useGtk=True): - """ - Configure the twisted mainloop to be run inside the gtk mainloop. -@@ -422,10 +123,8 @@ - return reactor - - -- - if runtime.platform.getType() != 'posix': - install = portableInstall - - -- - __all__ = ['install'] ---- /dev/null -+++ b/twisted/internet/gtk3reactor.py -@@ -0,0 +1,60 @@ -+# Copyright (c) Twisted Matrix Laboratories. -+# See LICENSE for details. -+ -+""" -+This module provides support for Twisted to interact with the gtk3 mainloop -+via Gobject introspection. This is like gi, but slightly slower and requires a -+working $DISPLAY. -+ -+In order to use this support, simply do the following:: -+ -+ from twisted.internet import gtk3reactor -+ gtk3reactor.install() -+ -+Then use twisted.internet APIs as usual. -+""" -+ -+from twisted.internet import gireactor -+from twisted.python import runtime -+ -+ -+class Gtk3Reactor(gireactor.GIReactor): -+ """ -+ A reactor using the gtk3+ event loop. -+ """ -+ -+ def __init__(self): -+ """ -+ Override init to set the C{useGtk} flag. -+ """ -+ gireactor.GIReactor.__init__(self, useGtk=True) -+ -+ -+ -+class PortableGtk3Reactor(gireactor.PortableGIReactor): -+ """ -+ Portable GTK+ 3.x reactor. -+ """ -+ def __init__(self): -+ """ -+ Override init to set the C{useGtk} flag. -+ """ -+ gireactor.PortableGIReactor.__init__(self, useGtk=True) -+ -+ -+ -+def install(): -+ """ -+ Configure the Twisted mainloop to be run inside the gtk3+ mainloop. -+ """ -+ if runtime.platform.getType() == 'posix': -+ reactor = Gtk3Reactor() -+ else: -+ reactor = PortableGtk3Reactor() -+ -+ from twisted.internet.main import installReactor -+ installReactor(reactor) -+ return reactor -+ -+ -+__all__ = ['install'] ---- a/twisted/internet/test/reactormixins.py -+++ b/twisted/internet/test/reactormixins.py -@@ -56,20 +56,26 @@ - # it's not _really_ worth it to support on other platforms, - # since no one really wants to use it on other platforms. - _reactors.extend([ -+ "twisted.internet.gireactor.PortableGIReactor", -+ "twisted.internet.gtk3reactor.PortableGtk3Reactor", - "twisted.internet.gtk2reactor.PortableGtkReactor", - "twisted.internet.win32eventreactor.Win32Reactor", - "twisted.internet.iocpreactor.reactor.IOCPReactor"]) - else: - _reactors.extend([ -+ "twisted.internet.gireactor.GIReactor", -+ "twisted.internet.gtk3reactor.Gtk3Reactor", - "twisted.internet.glib2reactor.Glib2Reactor", -- "twisted.internet.gtk2reactor.Gtk2Reactor", -- "twisted.internet.kqreactor.KQueueReactor"]) -+ "twisted.internet.gtk2reactor.Gtk2Reactor"]) - if platform.isMacOSX(): - _reactors.append("twisted.internet.cfreactor.CFReactor") - else: - _reactors.extend([ - "twisted.internet.pollreactor.PollReactor", -- "twisted.internet.epollreactor.EPollReactor"]) -+ "twisted.internet.epollreactor.EPollReactor", -+ # Support KQueue on non-OS-X POSIX platforms for now. -+ "twisted.internet.kqreactor.KQueueReactor", -+ ]) - - reactorFactory = None - originalHandler = None ---- a/twisted/plugins/twisted_reactors.py -+++ b/twisted/plugins/twisted_reactors.py -@@ -11,6 +11,10 @@ - 'select', 'twisted.internet.selectreactor', 'select(2)-based reactor.') - wx = Reactor( - 'wx', 'twisted.internet.wxreactor', 'wxPython integration reactor.') -+gi = Reactor( -+ 'gi', 'twisted.internet.gireactor', 'GObject Introspection integration reactor.') -+gtk3 = Reactor( -+ 'gtk3', 'twisted.internet.gtk3reactor', 'Gtk3 integration reactor.') - gtk = Reactor( - 'gtk', 'twisted.internet.gtkreactor', 'Gtk1 integration reactor.') - gtk2 = Reactor( diff -Nru twisted-12.0.0/debian/patches/01_posix_wakeups.patch twisted-12.2.0/debian/patches/01_posix_wakeups.patch --- twisted-12.0.0/debian/patches/01_posix_wakeups.patch 2012-05-15 15:18:22.000000000 +0000 +++ twisted-12.2.0/debian/patches/01_posix_wakeups.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -=== modified file 'twisted/internet/posixbase.py' ---- old/twisted/internet/posixbase.py 2011-10-16 19:13:26 +0000 -+++ new/twisted/internet/posixbase.py 2011-12-08 03:37:41 +0000 -@@ -265,6 +265,11 @@ class PosixReactorBase(_SignalReactorMix - self.removeWriter(selectable) - selectable.connectionLost(failure.Failure(why)) - -+ -+ # Callable that creates a waker, overrideable so that subclasses can -+ # substitute their own implementation: -+ _wakerFactory = _Waker -+ - def installWaker(self): - """ - Install a `waker' to allow threads and signals to wake up the IO thread. -@@ -273,7 +278,7 @@ class PosixReactorBase(_SignalReactorMix - the reactor. On Windows we use a pair of sockets. - """ - if not self.waker: -- self.waker = _Waker(self) -+ self.waker = self._wakerFactory(self) - self._internalReaders.add(self.waker) - self.addReader(self.waker) - - -=== modified file 'twisted/internet/test/test_threads.py' ---- old/twisted/internet/test/test_threads.py 2011-06-13 22:20:22 +0000 -+++ new/twisted/internet/test/test_threads.py 2011-12-08 03:37:41 +0000 -@@ -8,7 +8,7 @@ Tests for implementations of L{IReactorT - __metaclass__ = type - - from weakref import ref --import gc -+import gc, threading - - from twisted.python.threadable import isInIOThread - from twisted.internet.test.reactormixins import ReactorBuilder -@@ -104,6 +104,24 @@ class ThreadTestsBuilder(ReactorBuilder) - self.assertTrue(after - before < 30) - - -+ def test_callFromThread(self): -+ """ -+ A function scheduled with L{IReactorThreads.callFromThread} invoked -+ from another thread is run in the reactor thread. -+ """ -+ reactor = self.buildReactor() -+ result = [] -+ -+ def threadCall(): -+ result.append(threading.currentThread()) -+ reactor.stop() -+ reactor.callLater(0, reactor.callInThread, -+ reactor.callFromThread, threadCall) -+ self.runReactor(reactor, 5) -+ -+ self.assertEquals(result, [threading.currentThread()]) -+ -+ - def test_stopThreadPool(self): - """ - When the reactor stops, L{ReactorBase._stopThreadPool} drops the - -=== modified file 'twisted/internet/test/test_time.py' ---- old/twisted/internet/test/test_time.py 2011-02-14 04:45:15 +0000 -+++ new/twisted/internet/test/test_time.py 2011-12-08 03:37:41 +0000 -@@ -7,6 +7,7 @@ Tests for implementations of L{IReactorT - - __metaclass__ = type - -+from twisted.python.runtime import platform - from twisted.internet.test.reactormixins import ReactorBuilder - - -@@ -23,4 +24,38 @@ class TimeTestsBuilder(ReactorBuilder): - reactor.run() - - -+ -+class GlibTimeTestsBuilder(ReactorBuilder): -+ """ -+ Builder for defining tests relating to L{IReactorTime} for reactors based -+ off glib. -+ """ -+ if platform.isWindows(): -+ _reactors = ["twisted.internet.gtk2reactor.PortableGtkReactor"] -+ else: -+ _reactors = ["twisted.internet.glib2reactor.Glib2Reactor", -+ "twisted.internet.gtk2reactor.Gtk2Reactor"] -+ -+ def test_timeout_add(self): -+ """ -+ A C{reactor.callLater} call scheduled from a C{gobject.timeout_add} -+ call is run on time. -+ """ -+ import gobject -+ reactor = self.buildReactor() -+ -+ result = [] -+ def gschedule(): -+ reactor.callLater(0, callback) -+ return 0 -+ def callback(): -+ result.append(True) -+ reactor.stop() -+ -+ reactor.callWhenRunning(gobject.timeout_add, 10, gschedule) -+ self.runReactor(reactor, 5) -+ self.assertEqual(result, [True]) -+ -+ - globals().update(TimeTestsBuilder.makeTestCaseClasses()) -+globals().update(GlibTimeTestsBuilder.makeTestCaseClasses()) - diff -Nru twisted-12.0.0/debian/patches/series twisted-12.2.0/debian/patches/series --- twisted-12.0.0/debian/patches/series 2012-05-15 19:22:46.000000000 +0000 +++ twisted-12.2.0/debian/patches/series 2012-09-11 11:12:57.000000000 +0000 @@ -1,2 +1 @@ -00_gi_gtk3reactor.patch tap2deb.diff diff -Nru twisted-12.0.0/debian/rules twisted-12.2.0/debian/rules --- twisted-12.0.0/debian/rules 2012-05-15 15:18:51.000000000 +0000 +++ twisted-12.2.0/debian/rules 2012-09-11 11:12:57.000000000 +0000 @@ -53,14 +53,15 @@ dh_movefiles -ppython-twisted-bin \ --sourcedir=debian/python-twisted-core \ $(call py_libdir,$*)/twisted/internet/_sigchld.so \ - $(call py_libdir,$*)/twisted/python/_epoll.so \ $(call py_libdir,$*)/twisted/python/_initgroups.so \ + $(call py_libdir,$*)/twisted/python/sendmsg.so \ $(call py_libdir,$*)/twisted/test/raiser.so else dh_movefiles -ppython-twisted-bin \ --sourcedir=debian/python-twisted-core \ $(call py_libdir,$*)/twisted/internet/_sigchld.so \ $(call py_libdir,$*)/twisted/python/_initgroups.so \ + $(call py_libdir,$*)/twisted/python/sendmsg.so \ $(call py_libdir,$*)/twisted/test/raiser.so endif diff -Nru twisted-12.0.0/doc/development/index.html twisted-12.2.0/doc/development/index.html --- twisted-12.0.0/doc/development/index.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/index.html 2012-08-31 12:37:50.000000000 +0000 @@ -21,6 +21,6 @@

Index

- Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/naming.html twisted-12.2.0/doc/development/naming.html --- twisted-12.0.0/doc/development/naming.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/naming.html 2012-08-31 12:37:50.000000000 +0000 @@ -33,6 +33,6 @@

Index

- Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/philosophy.html twisted-12.2.0/doc/development/philosophy.html --- twisted-12.0.0/doc/development/philosophy.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/philosophy.html 2012-08-31 12:37:50.000000000 +0000 @@ -53,6 +53,6 @@

Index

- Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/policy/coding-standard.html twisted-12.2.0/doc/development/policy/coding-standard.html --- twisted-12.0.0/doc/development/policy/coding-standard.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/policy/coding-standard.html 2012-08-31 12:37:51.000000000 +0000 @@ -14,7 +14,7 @@

Try to choose names which are both easy to remember and meaningful. Some silliness is OK at the module naming level - (see twisted.spread...) but when + (see twisted.spread...) but when choosing class names, be as precise as possible.

Try to avoid overloaded terms. This rule is often broken, @@ -64,7 +64,7 @@ example of what you should write). The names of test modules should begin with test_ so that they are automatically discoverable by test runners such as Trial. Twisted's unit tests are written using - twisted.trial, an xUnit library which has been + twisted.trial, an xUnit library which has been extensively customized for use in testing Twisted and Twisted-based libraries.

@@ -398,7 +398,7 @@ to run from the command-line, the following things must be done:

    -
  1. Write a module in twisted.scripts +
  2. Write a module in twisted.scripts which contains a callable global named run. This will be called by the command line part with no arguments (it will usually read sys.argv). Feel free to write more @@ -507,7 +507,7 @@ in favor of the set and frozenset builtins. When you need to use sets or frozensets in your code, please use the set and frozenset provided - by twisted.python.compat. There are some + by twisted.python.compat. There are some differences between sets.Set and set, that are explained in the set PEP. Please be sure to not rely on the behavior of one or the other @@ -586,8 +586,8 @@

    Callback Arguments

    There are several methods whose purpose is to help the user set up - callback functions, for example Deferred.addCallback or the - reactor's callLater method. To make + callback functions, for example Deferred.addCallback or the + reactor's callLater method. To make access to the callback as transparent as possible, most of these methods use **kwargs to capture arbitrary arguments that are destined for the user's callback. This allows the call to the @@ -596,7 +596,7 @@

    In these methods, take care to not have other argument names that will steal the user's callback's arguments. When sensible, prefix these - internal argument names with an underscore. For example, RemoteReference.callRemote is + internal argument names with an underscore. For example, RemoteReference.callRemote is meant to be called like this:

    1 @@ -813,6 +813,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/policy/doc-standard.html twisted-12.2.0/doc/development/policy/doc-standard.html --- twisted-12.0.0/doc/development/policy/doc-standard.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/policy/doc-standard.html 2012-08-31 12:37:51.000000000 +0000 @@ -141,8 +141,8 @@

    Rendered result:

    - To add a twisted.web.static.File - instance to a Resource + To add a twisted.web.static.File + instance to a Resource instance, do myResource.putChild("resourcePath", File("/tmp")).

    @@ -191,6 +191,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/policy/index.html twisted-12.2.0/doc/development/policy/index.html --- twisted-12.0.0/doc/development/policy/index.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/policy/index.html 2012-08-31 12:37:51.000000000 +0000 @@ -28,6 +28,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/policy/svn-dev.html twisted-12.2.0/doc/development/policy/svn-dev.html --- twisted-12.0.0/doc/development/policy/svn-dev.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/policy/svn-dev.html 2012-08-31 12:37:50.000000000 +0000 @@ -58,12 +58,12 @@

    Combinator

    In order to simplify the use of Subversion, we typically use -Divmod Combinator. +Divmod Combinator. You may find it to be useful, too. In particular, because Twisted uses branches for almost all feature development, if you plan to contribute to Twisted you will probably find Combinator very useful. For more details, see the Combinator website, as well as the - + UQDS page.

    Compiling C extensions

    @@ -225,6 +225,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/policy/test-standard.html twisted-12.2.0/doc/development/policy/test-standard.html --- twisted-12.0.0/doc/development/policy/test-standard.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/policy/test-standard.html 2012-08-31 12:37:51.000000000 +0000 @@ -137,7 +137,7 @@

    Most unit tests should also avoid waiting for real time to pass. Unit tests which construct and advance - a twisted.internet.task.Clock are fast and + a twisted.internet.task.Clock are fast and deterministic.

    The Global Reactor

    @@ -394,6 +394,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/policy/writing-standard.html twisted-12.2.0/doc/development/policy/writing-standard.html --- twisted-12.0.0/doc/development/policy/writing-standard.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/policy/writing-standard.html 2012-08-31 12:37:51.000000000 +0000 @@ -248,7 +248,7 @@ impose upon authors the need to have a few dummy functions: in Twisted documentation the most common example is where a function is needed to generate a Deferred and fire it after some time has passed. An example - might be this, where deferLater is used to fire a callback + might be this, where deferLater is used to fire a callback after a period of time:

    1 @@ -308,6 +308,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/development/security.html twisted-12.2.0/doc/development/security.html --- twisted-12.0.0/doc/development/security.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/development/security.html 2012-08-31 12:37:50.000000000 +0000 @@ -38,6 +38,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/examples/index.html twisted-12.2.0/doc/examples/index.html --- twisted-12.0.0/doc/examples/index.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/examples/index.html 2012-08-31 12:37:51.000000000 +0000 @@ -6,7 +6,7 @@

    Twisted code examples

    - +
    @@ -42,7 +42,7 @@

    Perspective Broker

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/examples/longex2.py twisted-12.2.0/doc/examples/longex2.py --- twisted-12.0.0/doc/examples/longex2.py 2003-10-28 11:51:38.000000000 +0000 +++ twisted-12.2.0/doc/examples/longex2.py 2012-05-31 17:58:56.000000000 +0000 @@ -1,4 +1,8 @@ -"""Example of doing arbitarily long calculations nicely in Twisted. +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Example of doing arbitarily long calculations nicely in Twisted. This is also a simple demonstration of twisted.protocols.basic.LineReceiver. This example uses generators to do the calculation. It also tries to be @@ -40,7 +44,7 @@ result is 1. In that, this example departs from doc/examples/longex.py, which errors out when trying to do this. """ -from __future__ import generators + from twisted.protocols import basic from twisted.internet import defer, protocol diff -Nru twisted-12.0.0/doc/examples/pbgtk2.py twisted-12.2.0/doc/examples/pbgtk2.py --- twisted-12.0.0/doc/examples/pbgtk2.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/doc/examples/pbgtk2.py 2012-05-31 17:58:56.000000000 +0000 @@ -1,9 +1,6 @@ # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -from __future__ import nested_scopes - from twisted.internet import gtk2reactor gtk2reactor.install() @@ -67,7 +64,7 @@ reactor.connectTCP(host, port, client_factory) creds = UsernamePassword(userName, password) client_factory.login(creds).addCallbacks(self._cbGotPerspective, self._ebFailedLogin) - + self.statusMsg("Contacting server...") def _cbGotPerspective(self, perspective): @@ -80,7 +77,7 @@ text = str(reason.value) else: text = str(reason) - + self.statusMsg(text) msg = gtk.MessageDialog(self._loginDialog, gtk.DIALOG_DESTROY_WITH_PARENT, diff -Nru twisted-12.0.0/doc/examples/ptyserv.py twisted-12.2.0/doc/examples/ptyserv.py --- twisted-12.0.0/doc/examples/ptyserv.py 2002-10-02 05:50:15.000000000 +0000 +++ twisted-12.2.0/doc/examples/ptyserv.py 2012-04-07 16:45:03.000000000 +0000 @@ -1,3 +1,16 @@ +# Copyright (c) Twisted Matrix Laboratories +# See LICENSE for details + +""" +A PTY server that spawns a shell upon connection. + +Run this example by typing in: +> python ptyserv.py + +Telnet to the server once you start it by typing in: +> telnet localhost 5823 +""" + from twisted.internet import reactor, protocol class FakeTelnet(protocol.Protocol): diff -Nru twisted-12.0.0/doc/examples/pyuidemo.py twisted-12.2.0/doc/examples/pyuidemo.py --- twisted-12.0.0/doc/examples/pyuidemo.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/doc/examples/pyuidemo.py 2012-04-14 00:36:38.000000000 +0000 @@ -3,6 +3,14 @@ # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +""" +Displays a frame with two buttons and a background image, using pyui library. + +Run this example by typing in: + python pyuidemo.py + +Select "Quit" button to exit demo. +""" import pyui from twisted.internet import reactor, pyuisupport diff -Nru twisted-12.0.0/doc/examples/recvfd.py twisted-12.2.0/doc/examples/recvfd.py --- twisted-12.0.0/doc/examples/recvfd.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/doc/examples/recvfd.py 2012-04-26 13:46:20.000000000 +0000 @@ -0,0 +1,90 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Client-side of an example for sending file descriptors between processes over +UNIX sockets. This client connects to a server listening on a UNIX socket and +waits for one file descriptor to arrive over the connection. It displays the +name of the file and the first 80 bytes it contains, then exits. + +To runb this example, run this program with one argument: a path giving the UNIX +socket the server side of this example is already listening on. For example: + + $ python recvfd.py /tmp/sendfd.sock + +See sendfd.py for the server side of this example. +""" + +if __name__ == '__main__': + import recvfd + raise SystemExit(recvfd.main()) + +import os, sys + +from zope.interface import implements + +from twisted.python.log import startLogging +from twisted.python.filepath import FilePath +from twisted.internet.defer import Deferred +from twisted.internet.interfaces import IFileDescriptorReceiver +from twisted.internet.protocol import Factory +from twisted.protocols.basic import LineOnlyReceiver +from twisted.internet.endpoints import UNIXClientEndpoint +from twisted.internet import reactor + +class ReceiveFDProtocol(LineOnlyReceiver): + implements(IFileDescriptorReceiver) + + descriptor = None + + def __init__(self): + self.whenDisconnected = Deferred() + + + def fileDescriptorReceived(self, descriptor): + # Record the descriptor sent to us + self.descriptor = descriptor + + + def lineReceived(self, line): + if self.descriptor is None: + print "Received %r without receiving descriptor!" % (line,) + else: + # Use the previously received descriptor, along with the newly + # provided information about which file it is, to present some + # information to the user. + data = os.read(self.descriptor, 80) + print "Received %r from the server." % (line,) + print "First 80 bytes are:\n%r\n" % (data,) + os.close(self.descriptor) + self.transport.loseConnection() + + + def connectionLost(self, reason): + self.whenDisconnected.callback(None) + + + +def main(): + address = FilePath(sys.argv[1]) + + startLogging(sys.stdout) + + factory = Factory() + factory.protocol = ReceiveFDProtocol + factory.quiet = True + + endpoint = UNIXClientEndpoint(reactor, address.path) + connected = endpoint.connect(factory) + + def succeeded(client): + return client.whenDisconnected + def failed(reason): + print "Could not connect:", reason.getErrorMessage() + def disconnected(ignored): + reactor.stop() + + connected.addCallbacks(succeeded, failed) + connected.addCallback(disconnected) + + reactor.run() diff -Nru twisted-12.0.0/doc/examples/sendfd.py twisted-12.2.0/doc/examples/sendfd.py --- twisted-12.0.0/doc/examples/sendfd.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/doc/examples/sendfd.py 2012-04-26 13:46:20.000000000 +0000 @@ -0,0 +1,83 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Server-side of an example for sending file descriptors between processes over +UNIX sockets. This server accepts connections on a UNIX socket and sends one +file descriptor to them, along with the name of the file it is associated with. + +To run this example, run this program with two arguments: a path giving a UNIX +socket to listen on (must not exist) and a path to a file to send to clients +which connect (must exist). For example: + + $ python sendfd.py /tmp/sendfd.sock /etc/motd + +It will listen for client connections until stopped (eg, using Control-C). Most +interesting behavior happens on the client side. + +See recvfd.py for the client side of this example. +""" + +if __name__ == '__main__': + import sendfd + raise SystemExit(sendfd.main()) + +import sys + +from twisted.python.log import startLogging +from twisted.python.filepath import FilePath +from twisted.internet.protocol import Factory +from twisted.protocols.basic import LineOnlyReceiver +from twisted.internet import reactor + +class SendFDProtocol(LineOnlyReceiver): + def connectionMade(self): + # Open the desired file and keep a reference to it - keeping it open + # until we know the other side has it. Closing it early will prevent + # it from actually being sent. + self.fObj = self.factory.content.open() + + # Tell the transport to send it. It is not necessarily sent when this + # method returns. The reactor may need to run for a while longer before + # that happens. + self.transport.sendFileDescriptor(self.fObj.fileno()) + + # Send along *at least* one byte, since one file descriptor was sent. + # In this case, send along the name of the file to let the other side + # have some idea what they're getting. + self.sendLine(self.factory.content.path) + + # Give the other side a minute to deal with this. If they don't close + # the connection by then, we will do it for them. + self.timeoutCall = reactor.callLater(60, self.transport.loseConnection) + + + def connectionLost(self, reason): + # Clean up the file object, it is no longer needed. + self.fObj.close() + self.fObj = None + + # Clean up the timeout, if necessary. + if self.timeoutCall.active(): + self.timeoutCall.cancel() + self.timeoutCall = None + + +def main(): + address = FilePath(sys.argv[1]) + content = FilePath(sys.argv[2]) + + if address.exists(): + raise SystemExit("Cannot listen on an existing path") + + if not content.isfile(): + raise SystemExit("Content file must exist") + + startLogging(sys.stdout) + + serverFactory = Factory() + serverFactory.content = content + serverFactory.protocol = SendFDProtocol + + port = reactor.listenUNIX(address.path, serverFactory) + reactor.run() diff -Nru twisted-12.0.0/doc/examples/threadedselect/pygamedemo.py twisted-12.2.0/doc/examples/threadedselect/pygamedemo.py --- twisted-12.0.0/doc/examples/threadedselect/pygamedemo.py 2006-10-04 11:53:22.000000000 +0000 +++ twisted-12.2.0/doc/examples/threadedselect/pygamedemo.py 2012-05-31 17:58:56.000000000 +0000 @@ -1,4 +1,10 @@ -from __future__ import generators +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Demonstration of how L{twisted.internet._threadedselect} might be used (this is +not an example showing the best way to integrate Twisted with pygame). +""" # import Twisted and install from twisted.internet import _threadedselect @@ -71,7 +77,7 @@ reactor.stop() elif event.type == KEYDOWN and event.key == K_ESCAPE: reactor.stop() - + pygame.quit() if __name__ == '__main__': diff -Nru twisted-12.0.0/doc/examples/tkinterdemo.py twisted-12.2.0/doc/examples/tkinterdemo.py --- twisted-12.0.0/doc/examples/tkinterdemo.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/doc/examples/tkinterdemo.py 2012-04-14 00:53:12.000000000 +0000 @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + + +""" +An example of using Twisted with Tkinter. +Displays a frame with buttons that responds to mouse clicks. + +Run this example by typing in: + python tkinterdemo.py +""" + + +from Tkinter import Tk, Frame, Button, LEFT +from twisted.internet import reactor, tksupport + + +class App(object): + + def onQuit(self): + print "Quit!" + reactor.stop() + + def onButton(self): + print "Hello!" + + def __init__(self, master): + frame = Frame(master) + frame.pack() + + q = Button(frame, text="Quit!", command=self.onQuit) + b = Button(frame, text="Hello!", command=self.onButton) + + q.pack(side=LEFT) + b.pack(side=LEFT) + + +if __name__ == '__main__': + root = Tk() + tksupport.install(root) + app = App(root) + reactor.run() diff -Nru twisted-12.0.0/doc/howto/amp.html twisted-12.2.0/doc/howto/amp.html --- twisted-12.0.0/doc/howto/amp.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/amp.html 2012-08-31 12:37:44.000000000 +0000 @@ -10,13 +10,13 @@
    -

    The purpose of this guide is to describe the uses for and usage of twisted.protocols.amp beyond what is explained in the API documentation. It will show you how to implement an AMP server which can respond to commands or interact directly with individual messages. It will also show you how to implement an AMP client which can issue commands to a server.

    +

    The purpose of this guide is to describe the uses for and usage of twisted.protocols.amp beyond what is explained in the API documentation. It will show you how to implement an AMP server which can respond to commands or interact directly with individual messages. It will also show you how to implement an AMP client which can issue commands to a server.

    AMP is a bidirectional command/response-oriented protocol intended to be extended with application-specific request types and handlers. Various simple data types are supported and support for new data types can be added by applications.

    Setting Up

    -

    AMP runs over a stream-oriented connection-based protocol, such as TCP or SSL. Before you can use any features of the AMP protocol, you need a connection. The protocol class to use to establish an AMP connection is AMP. Connection setup works as it does for almost all protocols in Twisted. For example, you can set up a listening AMP server using a server endpoint:

    +

    AMP runs over a stream-oriented connection-based protocol, such as TCP or SSL. Before you can use any features of the AMP protocol, you need a connection. The protocol class to use to establish an AMP connection is AMP. Connection setup works as it does for almost all protocols in Twisted. For example, you can set up a listening AMP server using a server endpoint:

    1 2 @@ -113,7 +113,7 @@

    Commands

    -

    Either side of an AMP connection can issue a command to the other side. Each kind of command is represented as a subclass of Command. A Command defines arguments, response values, and error conditions.

    +

    Either side of an AMP connection can issue a command to the other side. Each kind of command is represented as a subclass of Command. A Command defines arguments, response values, and error conditions.

    1 2 @@ -344,6 +344,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/application.html twisted-12.2.0/doc/howto/application.html --- twisted-12.0.0/doc/howto/application.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/application.html 2012-08-31 12:37:46.000000000 +0000 @@ -43,17 +43,17 @@ recommended tool for running Twisted applications.

    -

    The core component of the Twisted Application infrastructure is the twisted.application.service.Application object — an +

    The core component of the Twisted Application infrastructure is the twisted.application.service.Application object — an object which represents your application. However, Application doesn't provide anything that you'd want to manipulate directly. Instead, Application acts as -a container of any Services (objects implementing IService) that your application +a container of any Services (objects implementing IService) that your application provides. Most of your interaction with the Application infrastructure will be done through Services.

    By Service, we mean anything in your application that can be started and stopped. Typical services include web servers, FTP servers and SSH clients. Your Application object can contain many services, and can even -contain structured hierarchies of Services using IServiceCollections.

    +contain structured hierarchies of Services using IServiceCollections.

    Here's a simple example of constructing an Application object which represents an echo server that runs on TCP port 7001.

    @@ -103,7 +103,7 @@

    To handle start-up and configuration of your Twisted application, the Twisted Application infrastructure uses .tac files. -.tac are Python files which configure an Application object and assign this +.tac are Python files which configure an Application object and assign this object to the top-level variable application.

    The following is a simple example of a .tac file:

    @@ -217,13 +217,13 @@

    Alternatively, the logging behavior can be customized through an API -accessible from .tac files. The ILogObserver component can be +accessible from .tac files. The ILogObserver component can be set on an Application in order to customize the default log observer that twistd will use.

    -Here is an example of how to use DailyLogFile, which rotates the log once +Here is an example of how to use DailyLogFile, which rotates the log once per day.

    @@ -270,8 +270,8 @@ Services which allow you to make connections and listen for connections on TCP ports. @@ -282,8 +282,8 @@
    Services which listen and make connections over UNIX sockets.
    @@ -293,8 +293,8 @@
    Services which allow you to make SSL connections and run SSL servers.
    @@ -304,7 +304,7 @@
    Services which allow you to send and receive data over UDP

    See also the UDP documentation.

    @@ -316,8 +316,8 @@
    Services which send and receive data over UNIX datagram sockets.
    @@ -326,11 +326,11 @@
    A server for UDP socket methods that support multicast.
    -
    TimerService
    +
    TimerService
    A service to periodically call a function. @@ -340,12 +340,12 @@

    Service Collection

    -

    IServiceCollection objects contain -IService objects. -IService objects can be added to IServiceCollection by calling setServiceParent and detached -by using disownServiceParent.

    +

    IServiceCollection objects contain +IService objects. +IService objects can be added to IServiceCollection by calling setServiceParent and detached +by using disownServiceParent.

    -

    The standard implementation of IServiceCollection is MultiService, which also implements +

    The standard implementation of IServiceCollection is MultiService, which also implements IService. MultiService is useful for creating a new Service which combines two or more existing Services. For example, you could create a DNS Service as a MultiService which has a TCP and a UDP Service as children.

    @@ -393,6 +393,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/basics.html twisted-12.2.0/doc/howto/basics.html --- twisted-12.0.0/doc/howto/basics.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/basics.html 2012-08-31 12:37:45.000000000 +0000 @@ -13,11 +13,11 @@

    Application

    Twisted programs usually work -with twisted.application.service.Application. +with twisted.application.service.Application. This class usually holds all persistent configuration of a running server -- ports to bind to, places where connections to must be kept or attempted, periodic actions to do and almost everything else. It is -the root object in a tree of services implementing IService.

    +the root object in a tree of services implementing IService.

    Other HOWTOs describe how to write custom code for Applications, but this one describes how to use already written code (which can be @@ -95,6 +95,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/choosing-reactor.html twisted-12.2.0/doc/howto/choosing-reactor.html --- twisted-12.0.0/doc/howto/choosing-reactor.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/choosing-reactor.html 2012-08-31 12:37:43.000000000 +0000 @@ -6,18 +6,19 @@

    Choosing a Reactor and GUI Toolkit Integration

    - +

    Overview

    -

    Twisted provides a variety of implementations of the twisted.internet.reactor. The specialized +

    Twisted provides a variety of implementations of the twisted.internet.reactor. The specialized implementations are suited for different purposes and are designed to integrate better with particular platforms.

    -

    The select()-based reactor is Twisted's - cross-platform reactor.

    +

    The epoll()-based reactor is Twisted's default on + Linux. Other platforms use poll(), or the most + cross-platform reactor, select().

    Platform-specific reactor implementations exist for:

    @@ -40,6 +41,7 @@
    -

    PyUI

    +

    PyUI

    As with Tkinter, the support for integrating Twisted with a PyUI @@ -341,6 +390,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/clients.html twisted-12.2.0/doc/howto/clients.html --- twisted-12.0.0/doc/howto/clients.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/clients.html 2012-08-31 12:37:46.000000000 +0000 @@ -21,7 +21,7 @@

    At the base, the place where you actually implement the protocol parsing and handling, is the Protocol class. This class will usually be descended - from twisted.internet.protocol.Protocol. Most + from twisted.internet.protocol.Protocol. Most protocol handlers inherit either from this class or from one of its convenience children. An instance of the protocol class will be instantiated when you connect to the server and will go away when the connection is @@ -29,8 +29,8 @@ Protocol.

    The persistent configuration is kept in a Factory - class, which usually inherits from twisted.internet.protocol.Factory - (or twisted.internet.protocol.ClientFactory: see + class, which usually inherits from twisted.internet.protocol.Factory + (or twisted.internet.protocol.ClientFactory: see below). The default factory class just instantiates the Protocol and then sets the protocol's factory attribute to point to itself (the factory). This lets the Protocol access, and @@ -81,17 +81,17 @@

    This protocol connects to the server, sends it a welcome message, and then terminates the connection.

    -

    The connectionMade event is +

    The connectionMade event is usually where set up of the Protocol object happens, as well as any initial greetings (as in the WelcomeMessage protocol above). Any tearing down of - Protocol-specific objects is done in connectionLost.

    + Protocol-specific objects is done in connectionLost.

    Simple, single-use clients

    In many cases, the protocol only needs to connect to the server once, and the code just wants to get a connected instance of the protocol. In those - cases twisted.internet.endpoints provides the + cases twisted.internet.endpoints provides the appropriate API.

    1 @@ -143,7 +143,7 @@ in a factory. This means it's easy to change the mechanism you're using to connect, without changing the rest of your program. For example, to run the greeter example over SSL, the only change required is to instantiate an - SSL4ClientEndpoint instead of a + SSL4ClientEndpoint instead of a TCP4ClientEndpoint. To take advantage of this, functions and methods which initiates a new connection should generally accept an endpoint as an argument and let the caller construct it, rather than taking @@ -162,7 +162,7 @@ clientConnectionFailed and clientConnectionLost methods will not be called. -

    You may come across code using ClientCreator, an older API which is not as flexible as +

    You may come across code using ClientCreator, an older API which is not as flexible as the endpoint API. Rather than calling connect on an endpoint, such code will look like this:

    @@ -196,7 +196,7 @@

    To use the lower-level connection APIs, you will need to call one of the reactor.connect* methods directly. For these cases, you need a - ClientFactory. + ClientFactory. The ClientFactory is in charge of creating the Protocol and also receives events relating to the connection state. This allows it to do things like reconnect in the event of a @@ -257,8 +257,8 @@ reactor.run()

    -

    Note that clientConnectionFailed - is called when a connection could not be established, and that clientConnectionLost +

    Note that clientConnectionFailed + is called when a connection could not be established, and that clientConnectionLost is called when a connection was made and then disconnected.

    Reconnection

    @@ -287,7 +287,7 @@

    However, most programs that want this functionality should - implement ReconnectingClientFactory instead, + implement ReconnectingClientFactory instead, which tries to reconnect if a connection is lost or fails and which exponentially delays repeated reconnect attempts.

    @@ -717,17 +717,17 @@

    Further Reading

    -

    The Protocol +

    The Protocol class used throughout this document is a base implementation - of IProtocol + of IProtocol used in most Twisted applications for convenience. To learn about the complete IProtocol interface, see the API documentation for - IProtocol.

    + IProtocol.

    The transport attribute used in some examples in this - document provides the ITCPTransport interface. To learn + document provides the ITCPTransport interface. To learn about the complete interface, see the API documentation - for ITCPTransport.

    + for ITCPTransport.

    Interface classes are a way of specifying what methods and attributes an object has and how they behave. See the @@ -736,6 +736,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/components.html twisted-12.2.0/doc/howto/components.html --- twisted-12.0.0/doc/howto/components.html 2012-02-10 16:32:41.000000000 +0000 +++ twisted-12.2.0/doc/howto/components.html 2012-08-31 12:37:47.000000000 +0000 @@ -253,7 +253,7 @@ infrastructure. If each piece of code which wished to use an adapted object had to explicitly construct the adapter itself, the coupling between components would be too tight. We would like to achieve loose coupling, and this is -where twisted.python.components comes in.

    +where twisted.python.components comes in.

    First, we need to discuss Interfaces in more detail. As we mentioned earlier, an Interface is nothing more than a class which is used as a marker. @@ -505,8 +505,8 @@ subclass declares that it implements another interface, the implements will be inherited by default.

    -

    For example, pb.Root is a class -which implements IPBRoot. This interface indicates that an +

    For example, pb.Root is a class +which implements IPBRoot. This interface indicates that an object has remotely-invokable methods and can be used as the initial object served by a new Broker instance. It has an implements setting like:

    @@ -598,6 +598,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/constants.html twisted-12.2.0/doc/howto/constants.html --- twisted-12.0.0/doc/howto/constants.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/constants.html 2012-08-31 12:37:46.000000000 +0000 @@ -6,14 +6,14 @@

    Symbolic Constants

    - +

    Overview

    It is often useful to define names which will be treated as - constants. twisted.python.constants provides APIs + constants. twisted.python.constants provides APIs for defining such symbolic constants with minimal overhead and some useful features beyond those afforded by the common Python idioms for this task.

    @@ -23,7 +23,7 @@

    Constant Names

    Constants which have no value apart from their name and identity can be - defined by subclassing Names. + defined by subclassing Names. Consider this example, in which some HTTP request method constants are defined.

    1 @@ -86,6 +86,7 @@

     >>> list(METHOD.iterconstants())
     [<METHOD=GET>, <METHOD=PUT>, <METHOD=POST>, <METHOD=DELETE>]
    +>>>
       

    And constants can also be compared, either for equality or identity:

    @@ -153,7 +154,7 @@

    Constants With Values

    Constants with a particular associated value are supported by - the Values base + the Values base class. Consider this example, in which some HTTP status code constants are defined.

    @@ -249,25 +250,41 @@

    And, as with Names, a subclass of Values can define methods:

    -
    -from twisted.python.constants import ValueConstant, Values
    -class STATUS(Values):
    -    """
    +  

    1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +

    from twisted.python.constants import ValueConstant, Values +class STATUS(Values): + """ Constants representing various HTTP status codes. - """ - OK = ValueConstant("200") - NO_CONTENT = ValueConstant("204") - NOT_MODIFIED = ValueConstant("304") - NOT_FOUND = ValueConstant("404") - - @classmethod - def hasBody(cls, status): - """ + """ + OK = ValueConstant("200") + NO_CONTENT = ValueConstant("204") + NOT_MODIFIED = ValueConstant("304") + NOT_FOUND = ValueConstant("404") + + @classmethod + def hasBody(cls, status): + """ Return True if the given status is associated with a response body, False otherwise. - """ - return status in (cls.NO_CONTENT, cls.NOT_MODIFIED) -
    + """ + return status in (cls.NO_CONTENT, cls.NOT_MODIFIED) +

    This functionality can be used as any class methods are used:

    @@ -279,9 +296,161 @@ >>>
    +

    Constants As Flags

    + +

    Integers are often used as a simple set for constants. The values for + these constants are assigned as powers of two so that bits in the integer can + be set to represent them. Individual bits are often called flags. + Flags supports this + use-case, including allowing constants with particular bits to be set, for + interoperability with other tools.

    + +

    POSIX filesystem access control is traditionally done using a bitvector + defining which users and groups may perform which operations on a file. This + state might be represented using Flags as follows:

    + +

    1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +

    from twisted.python.constants import FlagConstant, Flags +class Permission(Flags): + """ + Constants representing user, group, and other access bits for reading, + writing, and execution. + """ + OTHER_EXECUTE = FlagConstant() + OTHER_WRITE = FlagConstant() + OTHER_READ = FlagConstant() + GROUP_EXECUTE = FlagConstant() + GROUP_WRITE = FlagConstant() + GROUP_READ = FlagConstant() + USER_EXECUTE = FlagConstant() + USER_WRITE = FlagConstant() + USER_READ = FlagConstant() +
    + +

    + As for the previous types of constants, these can be accessed as attributes + of the class object: +

    + +
    +>>> Permission.USER_READ
    +<Permission=USER_READ>
    +>>> Permission.USER_WRITE
    +<Permission=USER_WRITE>
    +>>> Permission.USER_EXECUTE
    +<Permission=USER_EXECUTE>
    +>>>
    +  
    + +

    These constant objects also have a value attribute giving + their integer value:

    + +
    +>>> Permission.USER_READ.value
    +256
    +>>>
    +  
    + +

    And these constants can be looked up by name or value:

    + +
    +>>> Permission.lookupByName('USER_READ') is Permission.USER_READ
    +True
    +>>> Permission.lookupByValue(256) is Permission.USER_READ
    +True
    +>>>
    +  
    + +

    Constants can also be combined using the logical operators & + (and), | (or), and ^ + (exclusive or). +

    + +
    +>>> Permission.USER_READ | Permission.USER_WRITE
    +<Permission={USER_READ,USER_WRITE}>
    +>>> (Permission.USER_READ | Permission.USER_WRITE) & Permission.USER_WRITE
    +<Permission=USER_WRITE>
    +>>> (Permission.USER_READ | Permission.USER_WRITE) ^ Permission.USER_WRITE
    +<Permission=USER_READ>
    +>>>
    +  
    + +

    The unary operator ~ (not) is also defined:

    + +
    +>>> ~Permission.USER_READ
    +<Permission={GROUP_EXECUTE,GROUP_READ,GROUP_WRITE,OTHER_EXECUTE,OTHER_READ,OTHER_WRITE,USER_EXECUTE,USER_WRITE}>
    +>>>
    +  
    + +

    Constants created using these operators also have a value + attribute.

    + +
    +>>> (~Permission.USER_WRITE).value
    +383
    +>>>
    +  
    + +

    + Note the care taken to ensure the ~ operator is applied first + and the valueattribute is looked up second. +

    + +

    A Flags subclass can also define methods, just as + a Names or Values subclass may. For example, + Permission might benefit from a method to format a flag as a + string in the traditional style. Consider this addition to that class:

    + +

    1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +

    from twisted.python import filepath +from twisted.python.constants import FlagConstant, Flags +class Permission(Flags): + ... + + @classmethod + def format(cls, permissions): + """ + Format permissions flags in the traditional 'rwxr-xr-x' style. + """ + return filepath.Permissions(permissions.value).shorthand() +
    + +

    Use this like any other class method:

    + +
    +>>> Permission.format(Permission.USER_READ | Permission.USER_WRITE | Permission.GROUP_READ | Permission.OTHER_READ)
    +'rw-r--r--'
    +>>>
    +  

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/cred.html twisted-12.2.0/doc/howto/cred.html --- twisted-12.0.0/doc/howto/cred.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/cred.html 2012-08-31 12:37:45.000000000 +0000 @@ -31,11 +31,11 @@

    To sketch out how this works - a Realm corresponds to an application domain and is in charge of avatars, which are network-accessible business logic objects. To connect this to an authentication database, a top-level object -called a Portal stores a +called a Portal stores a realm, and a number of credential checkers. Something that wishes to log in, -such as a Protocol, +such as a Protocol, stores a reference to the portal. Login consists of passing credentials and a -request interface (e.g. POP3's IMailbox) to the portal. The portal passes +request interface (e.g. POP3's IMailbox) to the portal. The portal passes the credentials to the appropriate credential checker, which returns an avatar ID. The ID is passed to the realm, which returns the appropriate avatar. For a Portal that has a realm that creates mailbox objects and a credential checker @@ -55,7 +55,7 @@

    This is the the core of login, the point of integration between all the objects in the cred system. There is one concrete implementation of Portal, and no interface - it does a very -simple task. A Portal +simple task. A Portal associates one (1) Realm with a collection of CredentialChecker instances. (More on those later.)

    @@ -64,9 +64,9 @@ This has only 2 methods -

      -
    • login(credentials, mind, *interfaces) +
    • login(credentials, mind, *interfaces) -

      The docstring is quite expansive (see twisted.cred.portal), but in +

      The docstring is quite expansive (see twisted.cred.portal), but in brief, this is what you call when you need to call in order to connect a user to the system. Typically you only pass in one interface, and the mind is None. The interfaces are the possible interfaces the returned @@ -82,7 +82,7 @@

      The logout method has to be called when the avatar is logged out. For POP3 this means when the protocol is disconnected or logged out, etc..

    • -
    • registerChecker(checker, *credentialInterfaces) +
    • registerChecker(checker, *credentialInterfaces)

      which adds a CredentialChecker to the portal. The optional list of interfaces are interfaces of credentials that the checker is able to check.

      @@ -90,7 +90,7 @@

      The CredentialChecker

      -

      This is an object implementing ICredentialsChecker which resolves some +

      This is an object implementing ICredentialsChecker which resolves some credentials to an avatar ID. Whether the credentials are stored in an in-memory data structure, an @@ -122,18 +122,18 @@ several method calls in order to determine a result.

      Twisted comes with a number of credentials interfaces and implementations -in the twisted.cred.credentials module, -such as IUsernamePassword -and IUsernameHashedPassword.

      +in the twisted.cred.credentials module, +such as IUsernamePassword +and IUsernameHashedPassword.

      The Realm

      A realm is an interface which connects your universe of business objects to the authentication system.

      -

      IRealm is another one-method interface:

      +

      IRealm is another one-method interface:

        -
      • requestAvatar(avatarId, mind, *interfaces) +
      • requestAvatar(avatarId, mind, *interfaces)

        This method will typically be called from 'Portal.login'. The avatarId is the one returned by a CredentialChecker.

        @@ -432,7 +432,7 @@

        To build a plugin for cred, you should first define an authType, a short one-word string that defines your plugin to the command-line. Once you have this, the convention is to create a file named myapp_plugins.py in the -twisted.plugins module path.

        +twisted.plugins module path.

        Below is an example file structure for an application that defines such a plugin:

        @@ -464,7 +464,7 @@

        Once you have created this structure within your application, you can create the code for your cred plugin by building a factory class which -implements ICheckerFactory. +implements ICheckerFactory. These factory classes should not consist of a tremendous amount of code. Most of the real application logic should reside in the cred checker itself. (For help on building those, scroll up.) @@ -561,6 +561,6 @@

        Index

        - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/debug-with-emacs.html twisted-12.2.0/doc/howto/debug-with-emacs.html --- twisted-12.0.0/doc/howto/debug-with-emacs.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/debug-with-emacs.html 2012-08-31 12:37:44.000000000 +0000 @@ -60,6 +60,6 @@ THE AUTHORS

Index

- Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/defer.html twisted-12.2.0/doc/howto/defer.html --- twisted-12.0.0/doc/howto/defer.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/defer.html 2012-08-31 12:37:44.000000000 +0000 @@ -11,7 +11,7 @@ -

This document is a guide to the behaviour of the twisted.internet.defer.Deferred object, and to various +

This document is a guide to the behaviour of the twisted.internet.defer.Deferred object, and to various ways you can use them when they are returned by functions.

This document assumes that you are familiar with the basic principle that @@ -36,7 +36,7 @@

Deferreds

-

Twisted uses the Deferred object to manage the callback +

Twisted uses the Deferred object to manage the callback sequence. The client application attaches a series of functions to the deferred to be called in order when the results of the asychronous request are available (this series of functions is known as a series of @@ -49,7 +49,7 @@

Callbacks

-

A twisted.internet.defer.Deferred is a promise that +

A twisted.internet.defer.Deferred is a promise that a function will at some point have a result. We can attach callback functions to a Deferred, and once it gets a result these callbacks will be called. In addition Deferreds allow the developer to register a callback for an error, @@ -280,7 +280,7 @@

  • When the result is ready, give it to the Deferred object. .callback(result) if the operation succeeded, .errback(failure) if it failed. Note that - failure is typically an instance of a twisted.python.failure.Failure + failure is typically an instance of a twisted.python.failure.Failure instance.
  • Deferred object triggers previously-added (call/err)back @@ -302,7 +302,7 @@ statements.
  • If an errback doesn't raise an exception or return a - twisted.python.failure.Failure + twisted.python.failure.Failure instance, switch to callback.
  • @@ -315,7 +315,7 @@ callbacks run, one after the other, as described above.

    If the errback is called instead of the callback (e.g. because a DB query -raised an error), then a twisted.python.failure.Failure is passed into the first +raised an error), then a twisted.python.failure.Failure is passed into the first errback (you can add multiple errbacks, just like with callbacks). You can think of your errbacks as being like except blocks of ordinary Python code.

    @@ -334,7 +334,7 @@ so be careful. Make sure your errbacks return a Failure (probably the one that was passed to it), or a meaningful return value for the next callback.

    -

    Also, twisted.python.failure.Failure instances have +

    Also, twisted.python.failure.Failure instances have a useful method called trap, allowing you to effectively do the equivalent of:

    @@ -372,7 +372,7 @@ it re-raises the error.

    There's another potential gotcha here. There's a -method twisted.internet.defer.Deferred.addCallbacks +method twisted.internet.defer.Deferred.addCallbacks which is similar to, but not exactly the same as, addCallback followed by addErrback. In particular, consider these two cases:

    1 @@ -515,7 +515,7 @@

    Our original implementation of authenticateUser expected isValidUser to be synchronous, but now we need to change it to handle both synchronous and asynchronous implementations of isValidUser. For this, we -use maybeDeferred to +use maybeDeferred to call isValidUser, ensuring that the result of isValidUser is a Deferred, even if isValidUser is a synchronous function:

    @@ -557,7 +557,7 @@

    Sometimes you want to be notified after several different events have all happened, rather than waiting for each one individually. For example, you may -want to wait for all the connections in a list to close. twisted.internet.defer.DeferredList is the way to do +want to wait for all the connections in a list to close. twisted.internet.defer.DeferredList is the way to do this.

    To create a DeferredList from multiple Deferreds, you simply pass a list of @@ -736,7 +736,7 @@

    A common use for DeferredList is to "join" a number of parallel asynchronous operations, finishing successfully if all of the operations were successful, or -failing if any one of the operations fails. In this case, twisted.internet.defer.gatherResults is a useful +failing if any one of the operations fails. In this case, twisted.internet.defer.gatherResults is a useful shortcut:

    1 @@ -893,6 +893,6 @@ DeferredList is confusing and usually avoided.

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/design.html twisted-12.2.0/doc/howto/design.html --- twisted-12.0.0/doc/howto/design.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/design.html 2012-08-31 12:37:47.000000000 +0000 @@ -133,7 +133,7 @@ they also follow this approach. You can use them independently because they are not stuck to each other. They communicate in well-defined ways, and only when that -communication provides some additional feature. Thus, you can use twisted.web with twisted.enterprise, but neither requires the other, because +communication provides some additional feature. Thus, you can use twisted.web with twisted.enterprise, but neither requires the other, because they are integrated around the concept of Deferreds.

    Your Twisted applications should follow this style as much as possible. @@ -249,6 +249,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/dirdbm.html twisted-12.2.0/doc/howto/dirdbm.html --- twisted-12.0.0/doc/howto/dirdbm.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/dirdbm.html 2012-08-31 12:37:46.000000000 +0000 @@ -12,14 +12,14 @@

    dirdbm.DirDBM

    -

    twisted.persisted.dirdbm.DirDBM is a DBM-like storage system. +

    twisted.persisted.dirdbm.DirDBM is a DBM-like storage system. That is, it stores mappings between keys and values, like a Python dictionary, except that it stores the values in files in a directory - each entry is a different file. The keys must always be strings, -as are the values. Other than that, DirDBM +as are the values. Other than that, DirDBM objects act just like Python dictionaries.

    -

    DirDBM is useful for cases +

    DirDBM is useful for cases when you want to store small amounts of data in an organized fashion, without having to deal with the complexity of a RDBMS or other sophisticated database. It is simple, easy to use, cross-platform, and doesn't require any external C libraries, unlike @@ -41,7 +41,7 @@

    dirdbm.Shelf

    Sometimes it is neccessary to persist more complicated objects than strings. -With some care, dirdbm.Shelf +With some care, dirdbm.Shelf can transparently persist them. Shelf works exactly like DirDBM, except that the values (but not the keys) can be arbitrary picklable objects. However, @@ -71,6 +71,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/endpoints.html twisted-12.2.0/doc/howto/endpoints.html --- twisted-12.0.0/doc/howto/endpoints.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/endpoints.html 2012-08-31 12:37:43.000000000 +0000 @@ -6,7 +6,7 @@

    Getting Connected with Endpoints

    - +
    @@ -18,8 +18,8 @@ that is usually invisible to the application passing data across it. Twisted strives to make the nature of the "wire" as transparent as possible, with highly abstract interfaces for passing and receiving data, -such as ITransport -and IProtocol.

    +such as ITransport +and IProtocol.

    However, the application can't be completely ignorant of the wire. In particular, it must do something to start the connection, and @@ -30,7 +30,7 @@ connect to it, and the other side does the connecting.

    In Twisted 10.1, several new interfaces were introduced to describe -each of these roles for stream-oriented connections: IStreamServerEndpoint and IStreamClientEndpoint. +each of these roles for stream-oriented connections: IStreamServerEndpoint and IStreamClientEndpoint. The word "stream", in this case, refers to endpoints which treat a connection as a continuous stream of bytes, rather than a sequence of discrete datagrams: TCP is a "stream" protocol whereas UDP is a "datagram" @@ -47,7 +47,7 @@ endpoints directly. However, in most programs, you will want to allow the user to specify where to listen or connect, in a way which will allow the user to request different strategies, without having to adjust your -program. In order to allow this, you should use clientFromString or serverFromString.

    +program. In order to allow this, you should use clientFromString or serverFromString.

    There's Not Much To It

    @@ -65,9 +65,9 @@

    Servers and Stopping

    -

    IStreamServerEndpoint.listen -returns a Deferred -that fires with an IListeningPort. +

    IStreamServerEndpoint.listen +returns a Deferred +that fires with an IListeningPort. Note that this deferred may errback. The most common cause of such an error would be that another program is already using the requested port number, but the exact cause may vary depending on what type of endpoint you are @@ -81,7 +81,7 @@ response to anything other than a full server shutdown (reactor.stop and / or twistd will usually handle that case for you), make sure you keep a reference around to that listening port object so you can -call IListeningPort.stopListening +call IListeningPort.stopListening on it. Finally, keep in mind that stopListening itself returns a Deferred, and the port may not have fully stopped listening until that Deferred has fired.

    @@ -94,22 +94,22 @@

    Clients and Cancelling

    -

    IStreamClientEndpoint.connect +

    IStreamClientEndpoint.connect will connect your protocol factory to a new outgoing connection attempt. It returns a Deferred which fires with the IProtocol returned from the factory's buildProtocol method.

    -

    Connection attempts may fail, and so that Deferred may also errback. If it does so, +

    Connection attempts may fail, and so that Deferred may also errback. If it does so, you will have to try again; your protocol won't be constructed, and no further attempts will be made.

    Connection attempts may also take a long time, and your users may become bored and wander off. If this happens, and your code decides, for whatever reason, that you've been waiting for the connection too long, you -can call Deferred.cancel -on the Deferred returned from connect, and the +can call Deferred.cancel +on the Deferred returned from connect, and the underlying machinery should give up on the connection. This should cause the -Deferred to errback, usually with CancelledError; although you should +Deferred to errback, usually with CancelledError; although you should consult the documentation for your particular endpoint type to see if it may do something different.

    @@ -141,7 +141,7 @@

    If you are writing an application and you need to construct endpoints yourself, you can allow users to specify arbitrary endpoints -described by a string using the clientFromString and serverFromString +described by a string using the clientFromString and serverFromString APIs. Since these APIs just take a string, they provide flexibility: if Twisted adds support for new types of endpoints (for example, IPv6 endpoints, or WebSocket endpoints), your application will automatically be @@ -152,7 +152,7 @@

    For many use-cases, especially the common case of a twistd plugin which runs a long-running server that just binds a simple port, you might not want to use the endpoints APIs directly. Instead, you may want to -construct an IService, using strports.service , which will fit +construct an IService, using strports.service , which will fit neatly into the required structure of the twistd plugin API . This doesn't give your application much control - the port starts listening at startup and stops listening at shutdown - but it does @@ -160,13 +160,72 @@ application will support.

    It is, however, almost always preferable to use an endpoint rather -than calling a lower-level APIs like connectTCP, listenTCP, +than calling a lower-level APIs like connectTCP, listenTCP, etc, directly. By accepting an arbitrary endpoint rather than requiring a specific reactor interface, you leave your application open to lots of interesting transport-layer extensibility for the future.

    + +

    Endpoint Types Included With Twisted

    + +

    The parser used by clientFromString and +serverFromString is extensible via third-party plugins, so the +endpoints available on your system depend on what packages you have installed. +However, Twisted itself includes a set of basic endpoints that will always be +available.

    + +

    Clients

    + +
      +
    • TCP. Supported arguments: host, port, timeout. timeout is optional. For + example, tcp:host=twistedmatrix.com:port=80:timeout=15. +
    • +
    • SSL. All TCP arguments are supported, plus: certKey, privateKey, + caCertsDir. certKey (optional) gives a filesystem path to a certificate (PEM + format). privateKey (optional) gives a filesystem path to a a private key + (PEM format). caCertsDir (optional) gives a filesystem path to a directory + containing trusted CA certificates to use to verify the server certificate. + For example, + ssl:host=twistedmatrix.com:port=443:caCertsDir=/etc/ssl/certs. +
    • +
    • UNIX. Supported arguments: path, timeout, checkPID. path gives a + filesystem path to a listening UNIX domain socket server. checkPID (optional) + enables a check of the lock file Twisted-based UNIX domain socket servers use + to prove they are still running. For + example, unix:path=/var/run/web.sock. +
    • +
    + +

    Servers

    + +
      +
    • TCP. Supported arguments: port, interface, backlog. interface and + backlog are optional. interface is an IP address to bind to. For example, + tcp:port=80:interface=192.168.1.1. +
    • +
    • SSL. All TCP arguments are supported, plus: certKey, privateKey, and + sslmethod. certKey (optional, defaults to the value of privateKey) gives a + filesystem path to a certificate (PEM format). privateKey gives a filesystem + path to a a private key (PEM format). sslmethod indicates which SSL/TLS + version to use (a value like TLSv1_METHOD). For example, + ssl:port=443:privateKey=/etc/ssl/server.pem:sslmethod=SSLv3_METHOD. +
    • +
    • UNIX. Supported arguments: address, mode, backlog, lockfile. address + gives a filesystem path to listen on with a UNIX domain socket server. mode + (optional) gives the filesystem permission/mode (in octal) to apply to that + socket. lockfile enables use of a separate lock file to prove the server is + still running. For example, unix:address=/var/run/web.sock:lockfile=1. +
    • +
    • systemd. Supported arguments: domain, index. domain indicates which + socket domain the inherited file descriptor belongs to (eg INET, INET6). + index indicates an offset into the array of file descriptors which have been + inherited from systemd. For + example, systemd:domain=INET6:index=3. +
    • +
    +

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/gendefer.html twisted-12.2.0/doc/howto/gendefer.html --- twisted-12.0.0/doc/howto/gendefer.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/gendefer.html 2012-08-31 12:37:44.000000000 +0000 @@ -11,7 +11,7 @@ -

    Deferred objects are +

    Deferred objects are signals that a function you have called does not yet have the data you want available. When a function returns a Deferred object, your calling function attaches callbacks to it to handle the data when available.

    @@ -45,7 +45,7 @@

    Run success callbacks with the given result. This can only be run once. Later calls to this or - errback will raise twisted.internet.defer.AlreadyCalledError. + errback will raise twisted.internet.defer.AlreadyCalledError. If further callbacks or errbacks are added after this point, addCallbacks will run the callbacks immediately.

    @@ -55,7 +55,7 @@

    Run error callbacks with the given failure. This can only be run once. Later calls to this or - callback will raise twisted.internet.defer.AlreadyCalledError. + callback will raise twisted.internet.defer.AlreadyCalledError. If further callbacks or errbacks are added after this point, addCallbacks will run the callbacks immediately.

    @@ -229,8 +229,8 @@

    While we can require that callers of our function wrap our synchronous -result in a Deferred using maybeDeferred, for the sake of API -compatibility it is better to return a Deferred ourselves using defer.succeed:

    +result in a Deferred using maybeDeferred, for the sake of API +compatibility it is better to return a Deferred ourselves using defer.succeed:

    1 2 @@ -258,7 +258,7 @@ return defer.succeed(result)

    -

    There is an equivalent defer.fail method to return a Deferred with the +

    There is an equivalent defer.fail method to return a Deferred with the errback chain already fired.

    Integrating blocking code with Twisted

    @@ -271,7 +271,7 @@ other than rewriting them.

    In this case, Twisted provides the ability to run the blocking code in a -separate thread rather than letting it block your application. The twisted.internet.threads.deferToThread function will set up +separate thread rather than letting it block your application. The twisted.internet.threads.deferToThread function will set up a thread to run your blocking function, return a Deferred and later fire that Deferred when the thread completes.

    @@ -406,6 +406,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/glossary.html twisted-12.2.0/doc/howto/glossary.html --- twisted-12.0.0/doc/howto/glossary.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/glossary.html 2012-08-31 12:37:45.000000000 +0000 @@ -17,15 +17,15 @@ An object that has been adapted, also called original. See Adapter. -
    Adapter
    +
    Adapter
    An object whose sole purpose is to implement an Interface for another object. See Interfaces and Adapters.
    -
    Application
    +
    Application
    - A twisted.application.service.Application. There are + A twisted.application.service.Application. There are HOWTOs on creating and manipulating them as a system-administrator, as well as using them in your code. @@ -38,15 +38,15 @@ are mailboxes, and so on.
    -
    Banana
    +
    Banana
    The low-level data marshalling layer of Twisted Spread. - See twisted.spread.banana. + See twisted.spread.banana.
    -
    Broker
    +
    Broker
    - A twisted.spread.pb.Broker, the object request + A twisted.spread.pb.Broker, the object request broker for Twisted Spread.
    @@ -59,37 +59,37 @@
    component
    - A special kind of (persistent) Adapter that works with a twisted.python.components.Componentized. See also Interfaces and Adapters. + A special kind of (persistent) Adapter that works with a twisted.python.components.Componentized. See also Interfaces and Adapters.
    -
    Componentized
    +
    Componentized
    A Componentized object is a collection of information, separated into domain-specific or role-specific instances, that all stick together and refer to each other. - Each object is an Adapter, which, in the + Each object is an Adapter, which, in the context of Componentized, we call components. See also Interfaces and Adapters.
    -
    conch
    +
    conch
    Twisted's SSH implementation.
    Connector
    Object used to interface between client connections and protocols, usually - used with a twisted.internet.protocol.ClientFactory - to give you control over how a client connection reconnects. See twisted.internet.interfaces.IConnector and Writing Clients. + used with a twisted.internet.protocol.ClientFactory + to give you control over how a client connection reconnects. See twisted.internet.interfaces.IConnector and Writing Clients.
    Consumer
    An object that consumes data from a Producer. See - twisted.internet.interfaces.IConsumer. + twisted.internet.interfaces.IConsumer.
    Cred
    - Twisted's authentication API, twisted.cred. See + Twisted's authentication API, twisted.cred. See Introduction to Twisted Cred and Twisted Cred usage.
    @@ -103,7 +103,7 @@
    credential checker
    Where authentication actually happens. See - ICredentialsChecker. + ICredentialsChecker.
    CVSToys
    @@ -116,9 +116,9 @@ Daemon is a Unix term; service is the Windows equivalent. -
    Deferred
    +
    Deferred
    - A instance of twisted.internet.defer.Deferred, an + A instance of twisted.internet.defer.Deferred, an abstraction for handling chains of callbacks and error handlers (errbacks). See the Deferring Execution HOWTO. @@ -126,7 +126,7 @@
    Enterprise
    - Twisted's RDBMS support. It contains twisted.enterprise.adbapi for asynchronous access to any + Twisted's RDBMS support. It contains twisted.enterprise.adbapi for asynchronous access to any standard DB-API 2.0 module. See Introduction to Twisted Enterprise for more details.
    @@ -137,15 +137,15 @@ .addErrback to handle errors. -
    Factory
    +
    Factory
    In general, an object that constructs other objects. In Twisted, a Factory - usually refers to a twisted.internet.protocol.Factory, which constructs + usually refers to a twisted.internet.protocol.Factory, which constructs Protocol instances for incoming or outgoing connections. See Writing Servers and Writing Clients.
    -
    Failure
    +
    Failure
    Basically, an asynchronous exception that contains traceback information; these are used for passing errors through asynchronous callbacks. @@ -162,14 +162,14 @@ Instance Messenger is a multi-protocol chat program that comes with Twisted. It can communicate via TOC with the AOL servers, via IRC, as well as via PB with - Twisted Words. See twisted.words.im. + Twisted Words. See twisted.words.im.
    Interface
    A class that defines and documents methods that a class conforming to that - interface needs to have. A collection of core twisted.internet interfaces can - be found in twisted.internet.interfaces. See also Interfaces and Adapters. + interface needs to have. A collection of core twisted.internet interfaces can + be found in twisted.internet.interfaces. See also Interfaces and Adapters.
    Jelly
    @@ -177,7 +177,7 @@ The serialization layer for Twisted Spread, although it can be used seperately from Twisted Spread as well. It is similar in purpose to Python's standard pickle module, but is more - network-friendly, and depends on a separate marshaller (Banana, in most cases). See twisted.spread.jelly. + network-friendly, and depends on a separate marshaller (Banana, in most cases). See twisted.spread.jelly.
    Lore
    @@ -194,11 +194,11 @@
    Microdom
    A partial DOM implementation using SUX. It is simple and - pythonic, rather than strictly standards-compliant. See twisted.web.microdom. + pythonic, rather than strictly standards-compliant. See twisted.web.microdom.
    Names
    -
    Twisted's DNS server, found in twisted.names.
    +
    Twisted's DNS server, found in twisted.names.
    Nevow
    The successor to Woven; available from Divmod. @@ -214,7 +214,7 @@
    The high-level object layer of Twisted Spread, implementing semantics for method calling and object copying, caching, and - referencing. See twisted.spread.pb. + referencing. See twisted.spread.pb.
    Portal
    @@ -227,14 +227,14 @@
    An object that generates data a chunk at a time, usually to be processed by a Consumer. See - twisted.internet.interfaces.IProducer. + twisted.internet.interfaces.IProducer.
    -
    Protocol
    +
    Protocol
    In general each network connection has its own Protocol instance to manage connection-specific state. There is a collection of standard - protocol implementations in twisted.protocols. See + protocol implementations in twisted.protocols. See also Writing Servers and Writing Clients.
    @@ -254,19 +254,19 @@
    (in Twisted Cred) stores avatars and perhaps general business logic. See - IRealm. + IRealm.
    -
    Resource
    +
    Resource
    - A twisted.web.resource.Resource, which are served + A twisted.web.resource.Resource, which are served by Twisted Web. Resources can be as simple as a static file on disk, or they can have dynamically generated content.
    Service
    - A twisted.application.service.Service. See Application howto for a description of how they + A twisted.application.service.Service. See Application howto for a description of how they relate to Applications.
    @@ -279,7 +279,7 @@
    SUX
    Small Uncomplicated XML, Twisted's simple XML -parser written in pure Python. See twisted.web.sux.
    +parser written in pure Python. See twisted.web.sux.
    TAC
    A Twisted Application Configuration is a Python @@ -293,7 +293,7 @@ Using the Utilities.
    Trial
    -
    twisted.trial, Twisted's unit-testing framework, +
    twisted.trial, Twisted's unit-testing framework, based on the unittest standard library module. See also Writing tests for Twisted code.
    Twisted Matrix Laboratories
    @@ -308,15 +308,15 @@ Reality has been superseded by the Imaginary project. -
    usage
    -
    The twisted.python.usage module, a replacement for +
    usage
    +
    The twisted.python.usage module, a replacement for the standard getopt module for parsing command-lines which is much easier to work with. See Parsing command-lines.
    Words
    Twisted Words is a multi-protocol chat server that uses the Perspective Broker protocol as its native -communication style. See twisted.words.
    +communication style. See twisted.words.
    Woven
    Web Object Visualization Environment. @@ -329,6 +329,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/index.html twisted-12.2.0/doc/howto/index.html --- twisted-12.0.0/doc/howto/index.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/index.html 2012-08-31 12:37:44.000000000 +0000 @@ -182,6 +182,9 @@
  • Tips for writing tests for Twisted code using Trial
    More information on writing tests.
  • + +
  • Extremely Low-Level Socket Operations
    + Using wrappers for sendmsg(2) and recvmsg(2).
  • @@ -231,6 +234,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/internet-overview.html twisted-12.2.0/doc/howto/internet-overview.html --- twisted-12.0.0/doc/howto/internet-overview.html 2012-02-10 16:32:41.000000000 +0000 +++ twisted-12.2.0/doc/howto/internet-overview.html 2012-08-31 12:37:45.000000000 +0000 @@ -20,29 +20,29 @@

    Twisted Internet contains the various interfaces to the reactor API, whose usage is documented in the low-level chapter. Those APIs -are IReactorCore, - IReactorTCP, - IReactorSSL, - IReactorUNIX, - IReactorUDP, - IReactorTime, - IReactorProcess, - IReactorMulticast -and IReactorThreads. +are IReactorCore, + IReactorTCP, + IReactorSSL, + IReactorUNIX, + IReactorUDP, + IReactorTime, + IReactorProcess, + IReactorMulticast +and IReactorThreads. The reactor APIs allow non-persistent calls to be made.

    Twisted Internet also covers the interfaces for the various transports, -in ITransport +in ITransport and friends. These interfaces allow Twisted network code to be written without regard to the underlying implementation of the transport.

    -

    The IProtocolFactory +

    The IProtocolFactory dictates how factories, which are usually a large part of third party code, are written.

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/listings/sendmsg/copy_descriptor.py twisted-12.2.0/doc/howto/listings/sendmsg/copy_descriptor.py --- twisted-12.0.0/doc/howto/listings/sendmsg/copy_descriptor.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/doc/howto/listings/sendmsg/copy_descriptor.py 2012-04-12 21:13:48.000000000 +0000 @@ -0,0 +1,35 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Demonstration of copying a file descriptor over an AF_UNIX connection using +sendmsg. +""" + +from os import pipe, read, write +from socket import SOL_SOCKET, socketpair +from struct import unpack, pack + +from twisted.python.sendmsg import SCM_RIGHTS, send1msg, recv1msg + +def main(): + foo, bar = socketpair() + reader, writer = pipe() + + # Send a copy of the descriptor. Notice that there must be at least one + # byte of normal data passed in. + sent = send1msg( + foo.fileno(), "\x00", 0, + [(SOL_SOCKET, SCM_RIGHTS, pack("i", reader))]) + + # Receive the copy, including that one byte of normal data. + data, flags, ancillary = recv1msg(bar.fileno(), 1024) + duplicate = unpack("i", ancillary[0][2])[0] + + # Demonstrate that the copy works just like the original + write(writer, "Hello, world") + print "Read from original (%d): %r" % (reader, read(reader, 6)) + print "Read from duplicate (%d): %r" % (duplicate, read(duplicate, 6)) + +if __name__ == '__main__': + main() diff -Nru twisted-12.0.0/doc/howto/listings/sendmsg/send_replacement.py twisted-12.2.0/doc/howto/listings/sendmsg/send_replacement.py --- twisted-12.0.0/doc/howto/listings/sendmsg/send_replacement.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/doc/howto/listings/sendmsg/send_replacement.py 2012-04-12 21:13:48.000000000 +0000 @@ -0,0 +1,21 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Demonstration of sending bytes over a TCP connection using sendmsg. +""" + +from socket import socketpair + +from twisted.python.sendmsg import send1msg, recv1msg + +def main(): + foo, bar = socketpair() + sent = send1msg(foo.fileno(), "Hello, world") + print "Sent", sent, "bytes" + (received, flags, ancillary) = recv1msg(bar.fileno(), 1024) + print "Received", repr(received) + print "Extra stuff, boring in this case", flags, ancillary + +if __name__ == '__main__': + main() diff -Nru twisted-12.0.0/doc/howto/listings/trial/calculus/base_3.py twisted-12.2.0/doc/howto/listings/trial/calculus/base_3.py --- twisted-12.0.0/doc/howto/listings/trial/calculus/base_3.py 2009-06-08 18:39:34.000000000 +0000 +++ twisted-12.2.0/doc/howto/listings/trial/calculus/base_3.py 2012-03-13 23:49:05.000000000 +0000 @@ -5,7 +5,7 @@ try: return map(int, args) except ValueError: - raise TypeError("Coudln't coerce arguments to integers: %s" % args) + raise TypeError("Couldn't coerce arguments to integers: %s" % args) def add(self, a, b): a, b = self._make_ints(a, b) diff -Nru twisted-12.0.0/doc/howto/logging.html twisted-12.2.0/doc/howto/logging.html --- twisted-12.0.0/doc/howto/logging.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/logging.html 2012-08-31 12:37:46.000000000 +0000 @@ -12,11 +12,11 @@

    Basic usage

    -

    Twisted provides a simple and flexible logging system in the twisted.python.log module. It has three commonly used +

    Twisted provides a simple and flexible logging system in the twisted.python.log module. It has three commonly used functions:

    -
    msg
    +
    msg
    Logs a new message. For example:

    1 2 @@ -25,9 +25,9 @@

    -
    err
    +
    err
    Writes a failure to the log, including traceback information (if any). - You can pass it a Failure or Exception instance, or + You can pass it a Failure or Exception instance, or nothing. If you pass something else, it will be converted to a string with repr and logged. @@ -44,7 +44,7 @@
    -
    startLogging
    +
    startLogging
    Starts logging to a given file-like object. For example:

    1

    log.startLogging(open('/var/log/foo.log', 'w')) @@ -82,9 +82,9 @@

    Log files

    -

    The twisted.python.logfile module provides +

    The twisted.python.logfile module provides some standard classes suitable for use with startLogging, such - as DailyLogFile, + as DailyLogFile, which will rotate the log to a new file once per day.

    Using the standard library logging module

    @@ -93,7 +93,7 @@ Python standard library logging module or you want to use its easy configuration but don't want to lose twisted-produced messages, the observer - PythonLoggingObserver + PythonLoggingObserver should be useful to you.

    @@ -132,7 +132,7 @@ registered. There can be any number of observers, and each can treat the event in any way desired. An example of - a log observer in Twisted is the emit method of FileLogObserver. + a log observer in Twisted is the emit method of FileLogObserver. FileLogObserver, used by startLogging, writes events to a log file. A log observer is just a callable that accepts a dictionary as its only argument. You can @@ -191,6 +191,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/options.html twisted-12.2.0/doc/howto/options.html --- twisted-12.0.0/doc/howto/options.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/options.html 2012-08-31 12:37:45.000000000 +0000 @@ -16,12 +16,12 @@

    There is frequently a need for programs to parse a UNIX-like command line program: options preceded by - or --, sometimes followed by a parameter, followed by - a list of arguments. The twisted.python.usage provides a class, + a list of arguments. The twisted.python.usage provides a class, Options, to facilitate such parsing.

    While Python has the getopt module for doing this, it provides a very low level of abstraction for options. - Twisted has a higher level of abstraction, in the class twisted.python.usage.Options. It uses + Twisted has a higher level of abstraction, in the class twisted.python.usage.Options. It uses Python's reflection facilities to provide an easy to use yet flexible interface to the command line. While most command line processors either force the application writer to write her own @@ -32,7 +32,7 @@ programmer to decide how much control she wants.

    The Options class is used by subclassing. Since - a lot of time it will be used in the twisted.tap package, where the local + a lot of time it will be used in the twisted.tap package, where the local conventions require the specific options parsing class to also be called Options, it is usually imported with

    1 @@ -363,7 +363,7 @@ verbosity to -3.

    -

    The usage.Options +

    The usage.Options class knows that these are parameter-less options, since the methods do not receive an argument. Here is an example for a method with a parameter:

    @@ -566,16 +566,16 @@

    Optionally, a special attribute, compData, may be defined on your Options subclass in order to provide more information to the shell-completion system. The attribute should be an instance of - Completions. See that class + Completions. See that class for further details.

    In addition, compData may be defined on parent classes in your inheritance hiearchy. The information from each - Completions instance will be + Completions instance will be aggregated when producing the final tab-completion results.

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/pb-clients.html twisted-12.2.0/doc/howto/pb-clients.html --- twisted-12.0.0/doc/howto/pb-clients.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/pb-clients.html 2012-08-31 12:37:45.000000000 +0000 @@ -12,7 +12,7 @@

    Overview

    -

    In all the IPerspective uses +

    In all the IPerspective uses we have shown so far, we ignored the mind argument and created a new Avatar for every connection. This is usually an easy design choice, and it works well for simple cases.

    @@ -357,6 +357,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/pb-copyable.html twisted-12.2.0/doc/howto/pb-copyable.html --- twisted-12.0.0/doc/howto/pb-copyable.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/pb-copyable.html 2012-08-31 12:37:45.000000000 +0000 @@ -14,17 +14,17 @@

    This chapter focuses on how to use PB to pass complex types (specifically class instances) to and from a remote process. The first section is on -simply copying the contents of an object to a remote process (pb.Copyable). The second covers how -to copy those contents once, then update them later when they change (Cacheable).

    +simply copying the contents of an object to a remote process (pb.Copyable). The second covers how +to copy those contents once, then update them later when they change (Cacheable).

    Motivation

    From the previous chapter, you've seen how to pass basic types to a remote process, by using them in the arguments or -return values of a callRemote function. However, +return values of a callRemote function. However, if you've experimented with it, you may have discovered problems when trying to pass anything more complicated than a primitive int/list/dict/string -type, or another pb.Referenceable object. At some point you want +type, or another pb.Referenceable object. At some point you want to pass entire objects between processes, instead of having to reduce them down to dictionaries on one end and then re-instantiating them on the other.

    @@ -52,7 +52,7 @@

    If you try to run this, you might hope that a suitable remote end which implements the remote_sendPond method would see that method get invoked with an instance from the LilyPond class. But instead, -you'll encounter the dreaded InsecureJelly exception. This is +you'll encounter the dreaded InsecureJelly exception. This is Twisted's way of telling you that you've violated a security restriction, and that the receiving end refuses to accept your object.

    @@ -117,7 +117,7 @@

    PB lets you specify the mapping from remote class names to local classes -with the setUnjellyableForClass function +with the setUnjellyableForClass function 1. @@ -352,8 +352,8 @@

    The sending side has a class called LilyPond. To make this eligble for transport through callRemote (either as an argument, a return value, or something referenced by either of those [like a -dictionary value]), it must inherit from one of the four Serializable classes. In this section, -we focus on Copyable. +dictionary value]), it must inherit from one of the four Serializable classes. In this section, +we focus on Copyable. The copyable subclass of LilyPond is called CopyPond. We create an instance of it and send it through callRemote as an argument to the receiver's @@ -362,8 +362,8 @@ copy_sender.CopyPond and some chunk of data that represents the object's state. pond.__class__.__module__ and pond.__class__.__name__ are used to derive the class name -string. The object's getStateToCopy method is -used to get the state: this is provided by pb.Copyable, and the default just retrieves +string. The object's getStateToCopy method is +used to get the state: this is provided by pb.Copyable, and the default just retrieves self.__dict__. This works just like the optional __getstate__ method used by pickle. The pair of name and state are sent over the wire to the receiver.

    @@ -374,7 +374,7 @@ of copy_sender.LilyPond), which specifies how we expect it to behave. We trust that this is the same LilyPond class as the sender used. (At the very least, we hope ours will be able to accept a state -created by theirs). It also inherits from pb.RemoteCopy, which is a requirement for all +created by theirs). It also inherits from pb.RemoteCopy, which is a requirement for all classes that act in this local-representative role (those which are given to the second argument of setUnjellyableForClass). RemoteCopy provides the methods that tell the Jelly layer how @@ -389,7 +389,7 @@

    When the receiver unserializes (unjellies) the object, it will create an instance of the local ReceiverPond class, and hand the transmitted state (usually in the form of a dictionary) to that object's - setCopyableState method. + setCopyableState method. This acts just like the __setstate__ method that pickle uses when unserializing an object. getStateToCopy/setCopyableState are distinct from @@ -686,8 +686,8 @@ defined together, with the setUnjellyableForClass immediately following them. -

  • The class that is sent must inherit from pb.Copyable. The class that is registered to - receive it must inherit from pb.RemoteCopy2.
  • +
  • The class that is sent must inherit from pb.Copyable. The class that is registered to + receive it must inherit from pb.RemoteCopy2.
  • The same class can be used to send and receive. Just have it inherit from both pb.Copyable and pb.RemoteCopy. This @@ -696,16 +696,16 @@ using setCopyableState) versus when it is going (using getStateToCopy).
  • -
  • InsecureJelly +
  • InsecureJelly exceptions are raised by the receiving end. They will be delivered asynchronously to an errback handler. If you do not add one to the Deferred returned by callRemote, then you will never receive notification of the problem.
  • -
  • The class that is derived from pb.RemoteCopy will be created using a +
  • The class that is derived from pb.RemoteCopy will be created using a constructor __init__ method that takes no arguments. All setup must be performed in the setCopyableState method. As - the docstring on RemoteCopy says, don't implement a + the docstring on RemoteCopy says, don't implement a constructor that requires arguments in a subclass of RemoteCopy.
  • @@ -723,11 +723,11 @@ in twisted.spread.flavors, and the docstrings there are the best source of additional information. -
  • Copyable is also used in twisted.web.distrib to deliver HTTP requests to other +
  • Copyable is also used in twisted.web.distrib to deliver HTTP requests to other programs for rendering, allowing subtrees of URL space to be delegated to multiple programs (on multiple machines).
  • -
  • twisted.manhole.explorer also uses +
  • twisted.manhole.explorer also uses Copyable to distribute debugging information from the program under test to the debugging tool.
  • @@ -741,15 +741,15 @@ processing) to represent its state. slow means that state doesn't change very frequently. It may be more efficient to send the full state only once, the first time it is needed, then afterwards only send the differences -or changes in state whenever it is modified. The pb.Cacheable class provides a framework to +or changes in state whenever it is modified. The pb.Cacheable class provides a framework to implement this.

    -

    pb.Cacheable is derived -from pb.Copyable, so it is +

    pb.Cacheable is derived +from pb.Copyable, so it is based upon the idea of an object's state being captured on the sending side, and then turned into a new object on the receiving side. This is extended to -have an object publishing on the sending side (derived from pb.Cacheable), matched with one -observing on the receiving side (derived from pb.RemoteCache).

    +have an object publishing on the sending side (derived from pb.Cacheable), matched with one +observing on the receiving side (derived from pb.RemoteCache).

    To effectively use pb.Cacheable, you need to isolate changes to your object into accessor functions (specifically setter @@ -757,8 +757,8 @@ attribute is changed3.

    You derive your sender-side class from pb.Cacheable, and you -add two methods: getStateToCacheAndObserveFor -and stoppedObserving. The first +add two methods: getStateToCacheAndObserveFor +and stoppedObserving. The first is called when a remote caching reference is first created, and retrieves the data with which the cache is first filled. It also provides an object called the observer 4 that points at that receiver-side cache. Every time the state of the object @@ -766,7 +766,7 @@ change. The other method, stoppedObserving, is called when the remote cache goes away, so that you can stop sending updates.

    -

    On the receiver end, you make your cache class inherit from pb.RemoteCache, and implement the +

    On the receiver end, you make your cache class inherit from pb.RemoteCache, and implement the setCopyableState as you would for a pb.RemoteCopy object. In addition, you must implement methods to receive the updates sent to the observer by the pb.Cacheable: these methods should have @@ -793,7 +793,7 @@ Just before it dies, it tells the sender side it no longer cares about the original object. When that reference count goes to zero, the Observer goes away and the pb.Cacheable object can stop -announcing every change that takes place. The stoppedObserving method is +announcing every change that takes place. The stoppedObserving method is used to tell the pb.Cacheable that the Observer has gone away.

    @@ -1134,13 +1134,13 @@ @@ -1160,26 +1160,26 @@ that are the Unjellyable second argument of the setUnjellyableForClass function. In particular, unjellyable does not mean cannot be -jellied. Unpersistable means not +jellied. Unpersistable means not persistable, but unjelly, unserialize, and unpickle mean to reverse the operations of jellying, serializing, and -pickling.
  • pb.RemoteCopy is actually defined - in twisted.spread.flavors, but +pickling.
  • pb.RemoteCopy is actually defined + in twisted.spread.flavors, but pb.RemoteCopy is the preferred way to access it
  • Of course you could be clever and add a hook to __setattr__, along with magical change-announcing subclasses of the usual builtin types, to detect changes that result from normal = set operations. The semi-magical property attributes that were introduced in Python 2.2 could be useful too. The result might be -hard to maintain or extend, though.
  • This is actually a RemoteCacheObserver, but it isn't very +hard to maintain or extend, though.
  • This is actually a RemoteCacheObserver, but it isn't very useful to subclass or modify, so simply treat it as a little demon that sits in your pb.Cacheable class and helps you distribute change notifications. The only useful thing to do with it is to run its callRemote method, which acts just like a normal pb.Referenceable's method of the same name.
  • This applies to - multiple references through the same Broker. If you've managed to make multiple + multiple references through the same Broker. If you've managed to make multiple TCP connections to the same program, you deserve whatever you get.
  • Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/pb-cred.html twisted-12.2.0/doc/howto/pb-cred.html --- twisted-12.0.0/doc/howto/pb-cred.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/pb-cred.html 2012-08-31 12:37:47.000000000 +0000 @@ -305,7 +305,7 @@

    This technique also relies upon the fact that the pb.Referenceable reference can only come from someone who holds a corresponding pb.RemoteReference. The design of the -serialization mechanism (implemented in twisted.spread.jelly: pb, jelly, spread.. get it? Look for +serialization mechanism (implemented in twisted.spread.jelly: pb, jelly, spread.. get it? Look for banana, too. What other networking framework can claim API names based on sandwich ingredients?) makes it impossible for a client to obtain a reference that they weren't explicitly given. @@ -1229,8 +1229,8 @@

    pbAnonServer.py implements a server based on pb6server.py, extending it to permit anonymous logins in addition to authenticated logins. An - AllowAnonymousAccess -checker and an InMemoryUsernamePasswordDatabaseDontUse + AllowAnonymousAccess +checker and an InMemoryUsernamePasswordDatabaseDontUse checker are registered and the client's choice of credentials object determines which is used to authenticate the login. In either case, the realm will be called on to create an avatar for @@ -1238,8 +1238,8 @@ of twisted.cred.checkers.ANONYMOUS.

    On the client side, the only change is the use of an instance of - Anonymous when calling - PBClientFactory.login.

    + Anonymous when calling + PBClientFactory.login.

    Using Avatars

    @@ -1426,7 +1426,7 @@

    Viewable

    Once you have IPerspective objects (i.e. the Avatar) to -represent users, the Viewable class can come into play. This +represent users, the Viewable class can come into play. This class behaves a lot like Referenceable: it turns into a RemoteReference when sent over the wire, and certain methods can be invoked by the holder of that reference. However, the methods that @@ -1719,6 +1719,6 @@ backwards-compatibility.

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/pb-intro.html twisted-12.2.0/doc/howto/pb-intro.html --- twisted-12.0.0/doc/howto/pb-intro.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/pb-intro.html 2012-08-31 12:37:43.000000000 +0000 @@ -33,7 +33,7 @@
  • remote method calls: doing something to a local object and causing a method to get run on a distant one. The local object is called a - RemoteReference, and you + RemoteReference, and you do something by running its .callRemote method.
  • @@ -54,13 +54,13 @@ @@ -69,15 +69,15 @@
      -
    • RemoteReference +
    • RemoteReference : spread/pb.py
    • -
    • pb.Root +
    • pb.Root : spread/pb.py, actually defined as twisted.spread.flavors.Root in spread/flavors.py
    • -
    • pb.Referenceable +
    • pb.Referenceable : spread/pb.py, actually defined as twisted.spread.flavors.Referenceable in spread/flavors.py
    • @@ -88,15 +88,15 @@ about authorization and security:

      Subclassing and Implementing

      @@ -110,17 +110,17 @@
        -
      • pb.Root, pb.Referenceable: you'll +
      • pb.Root, pb.Referenceable: you'll subclass these to make remotely-referenceable objects (i.e., objects which you can call methods on remotely) using PB. You don't need to change any of the existing behavior, just inherit all of it and add the remotely-accessible methods that you want to export.
      • -
      • pb.Avatar: You'll +
      • pb.Avatar: You'll be subclassing this when you get into PB programming with authorization. This is an implementor of IPerspective.
      • -
      • ICredentialsChecker: Implement this if +
      • ICredentialsChecker: Implement this if you want to authenticate your users against some sort of data store: i.e., an LDAP database, an RDBMS, etc. There are already a few implementations of this for various back-ends in @@ -133,14 +133,14 @@

        Things you can Call Remotely

        At this writing, there are three flavors of objects that can -be accessed remotely through RemoteReference objects. Each of these +be accessed remotely through RemoteReference objects. Each of these flavors has a rule for how the callRemote message is transformed into a local method call on the server. In order to use one of these flavors, subclass them and name your published methods with the appropriate prefix.

          -
        • twisted.spread.pb.IPerspective implementors +
        • twisted.spread.pb.IPerspective implementors

          This is the first interface we deal with. It is a perspective onto your PB application. Perspectives are slightly special because @@ -165,7 +165,7 @@

        • -
        • twisted.spread.pb.Referenceable +
        • twisted.spread.pb.Referenceable

          Referenceable objects are the simplest kind of PB object. You can call methods on them and return them from methods to provide access to other @@ -179,7 +179,7 @@

        • -
        • twisted.spread.pb.Viewable +
        • twisted.spread.pb.Viewable

          Viewable objects are remotely referenceable objects which have the additional requirement that it must be possible to tell who is calling them. @@ -208,13 +208,13 @@

            -
          • twisted.spread.pb.Copyable +
          • twisted.spread.pb.Copyable

            This is the simpler kind of object that can be copied. Every time this object is returned from a method or passed as an argument, it is serialized and unserialized.

            -

            Copyable +

            Copyable provides a method you can override, getStateToCopyFor(perspective), which allows you to decide what an object will look like for the perspective who is requesting it. The perspective argument will be the perspective @@ -249,7 +249,7 @@

          • -
          • twisted.spread.pb.Cacheable +
          • twisted.spread.pb.Cacheable

            Let me preface this with a warning: Cacheable may be hard to understand. The motivation for it may be unclear if you don't have some experience with @@ -279,13 +279,13 @@ perspective. It also gets passed an observer, which is a remote reference to a secret fourth referenceable flavor: - RemoteCache.

            + RemoteCache.

            -

            A RemoteCache is simply +

            A RemoteCache is simply the object that represents your - Cacheable on the other side + Cacheable on the other side of the connection. It is registered using the same method as - RemoteCopy, above. + RemoteCopy, above. RemoteCache is different, however, in that it will be referenced by its peer. It acts as a Referenceable, where all methods prefixed with observe_ will be callable remotely. It is @@ -295,11 +295,11 @@ that should be noticeable to its clients.

            Finally, when all references to a - Cacheable from a given + Cacheable from a given perspective are lost, stoppedObserving(perspective, observer) will be called on the - Cacheable, with the same + Cacheable, with the same perspective/observer pair that getStateToCacheAndObserveFor was originally called with. Any cleanup remote calls can be made there, as well as removing the observer object from any lists which it was previously in. @@ -315,6 +315,6 @@ now.

          • Index

            - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/pb-limits.html twisted-12.2.0/doc/howto/pb-limits.html --- twisted-12.0.0/doc/howto/pb-limits.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/pb-limits.html 2012-08-31 12:37:43.000000000 +0000 @@ -33,7 +33,7 @@ the size of long integers. The purpose of this limit is the same as the SIZE_LIMIT. By default, only integers between -2 ** 448 and 2 ** 448 (exclusive) can be transferred. This limit can be changed using - twisted.spread.banana.setPrefixLimit.

            + twisted.spread.banana.setPrefixLimit.

            Perspective Broker Limits

            @@ -46,6 +46,6 @@

            Index

            - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/pb-usage.html twisted-12.2.0/doc/howto/pb-usage.html --- twisted-12.0.0/doc/howto/pb-usage.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/pb-usage.html 2012-08-31 12:37:48.000000000 +0000 @@ -68,20 +68,20 @@

    First we look at the server. This defines an Echoer class (derived from - pb.Root), with a method called + pb.Root), with a method called remote_echo(). - pb.Root objects (because of + pb.Root objects (because of their inheritance of - pb.Referenceable, described + pb.Referenceable, described later) can define methods with names of the form remote_*; a client which obtains a remote reference to that - pb.Root object will be able to + pb.Root object will be able to invoke those methods.

    -

    The pb.Root-ish object is -given to a pb.PBServerFactory(). This is a - Factory object like -any other: the Protocol objects it creates for new +

    The pb.Root-ish object is +given to a pb.PBServerFactory(). This is a + Factory object like +any other: the Protocol objects it creates for new connections know how to speak the PB protocol. The object you give to pb.PBServerFactory() becomes the root object, which simply makes it available for the client to retrieve. The client may only @@ -89,11 +89,11 @@ implement your security model. Because it is so common to export just a single object (and because a remote_* method on that one can return a reference to any other object you might want to give out), the -simplest example is one where the PBServerFactory is given the root object, and +simplest example is one where the PBServerFactory is given the root object, and the client retrieves it.

    The client side uses - pb.PBClientFactory to make a + pb.PBClientFactory to make a connection to a given port. This is a two-step process involving opening a TCP connection to a given host and port and requesting the root object using .getRootObject().

    @@ -102,7 +102,7 @@ connection has been made and exchange some data, it may take a while, so it returns a Deferred, to which the gotObject() callback is attached. (See the documentation on Deferring -Execution for a complete explanation of Deferreds). If and when the +Execution for a complete explanation of Deferreds). If and when the connection succeeds and a reference to the remote root object is obtained, this callback is run. The first argument passed to the callback is a remote reference to the distant root object. (you can @@ -119,10 +119,10 @@ (running .callRemote("boom") would cause .remote_boom() to be run, etc). Again because of the delay involved, callRemote() returns a - Deferred. Assuming the + Deferred. Assuming the remote method was run without causing an exception (including an attempt to invoke an unknown method), the callback attached to that - Deferred will be + Deferred will be invoked with any objects that were returned by the remote method call.

    In this example, the server's Echoer object has a method @@ -135,8 +135,8 @@

    and from the definition of remote_echo() we see that this just returns the same string it was given: hello network.

    -

    From the client's point of view, the remote call gets another Deferred object instead of -that string. callRemote() always returns a Deferred. This is why PB is +

    From the client's point of view, the remote call gets another Deferred object instead of +that string. callRemote() always returns a Deferred. This is why PB is described as a system for translucent remote method calls instead of transparent ones: you cannot pretend that the remote object is really local. Trying to do so (as some other RPC mechanisms do, coughCORBAcough) @@ -144,17 +144,17 @@ Deferreds turns out to be a very clean way to deal with the whole thing.

    The remote reference object (the one given to - getRootObject()'s success callback) is an instance the RemoteReference class. This means + getRootObject()'s success callback) is an instance the RemoteReference class. This means you can use it to invoke methods on the remote object that it refers to. Only -instances of RemoteReference are eligible for - .callRemote(). The RemoteReference object is the one that lives +instances of RemoteReference are eligible for + .callRemote(). The RemoteReference object is the one that lives on the remote side (the client, in this case), not the local side (where the actual object is defined).

    In our example, the local object is that Echoer() instance, -which inherits from pb.Root, +which inherits from pb.Root, which inherits from - pb.Referenceable. It is that + pb.Referenceable. It is that Referenceable class that makes the object eligible to be available for remote method calls1. If you have an object that is Referenceable, then any client that manages to get a @@ -167,31 +167,31 @@ remote_* methods can do.

    Also note: the other classes like - Referenceable allow access to + Referenceable allow access to other methods, in particular perspective_* and view_* may be accessed. Don't write local-only methods with these names, because then remote callers will be able to do more than you intended.

    Also also note: the other classes like - pb.Copyable do allow + pb.Copyable do allow access to attributes, but you control which ones they can see.

    You don't have to be a - pb.Root to be remotely callable, + pb.Root to be remotely callable, but you do have to be - pb.Referenceable. (Objects that -inherit from pb.Referenceable -but not from pb.Root can be + pb.Referenceable. (Objects that +inherit from pb.Referenceable +but not from pb.Root can be remotely called, but only - pb.Root-ish objects can be given -to the PBServerFactory.)

    + pb.Root-ish objects can be given +to the PBServerFactory.)

    Complete Example

    -

    Here is an example client and server which uses pb.Referenceable as a root object and as the +

    Here is an example client and server which uses pb.Referenceable as a root object and as the result of a remotely exposed method. In each context, methods can be invoked -on the exposed Referenceable +on the exposed Referenceable instance. In this example, the initial root object has a method that returns a reference to the second object.

    @@ -300,11 +300,11 @@ main()
    Source listing - listings/pb/pb1client.py
    -

    pb.PBClientFactory.getRootObject will +

    pb.PBClientFactory.getRootObject will handle all the details of waiting for the creation of a connection. -It returns a Deferred, which will have its +It returns a Deferred, which will have its callback called when the reactor connects to the remote server and - pb.PBClientFactory gets the + pb.PBClientFactory gets the root, and have its errback called when the object-connection fails for any reason, whether it was host lookup failure, connection refusal, or some server-side error. @@ -312,24 +312,24 @@

    The root object has a method called remote_getTwo, which returns the Two() instance. On the client end, the callback gets -a RemoteReference to that +a RemoteReference to that instance. The client can then invoke two's .remote_three() method.

    -

    RemoteReference +

    RemoteReference objects have one method which is their purpose for being: callRemote. This method allows you to call a -remote method on the object being referred to by the Reference. RemoteReference.callRemote, like pb.PBClientFactory.getRootObject, returns -a Deferred. -When a response to the method-call being sent arrives, the Deferred's callback or errback +remote method on the object being referred to by the Reference. RemoteReference.callRemote, like pb.PBClientFactory.getRootObject, returns +a Deferred. +When a response to the method-call being sent arrives, the Deferred's callback or errback will be made, depending on whether an error occurred in processing the method call.

    You can use this technique to provide access to arbitrary sets of objects. Just remember that any object that might get passed over the wire must -inherit from Referenceable +inherit from Referenceable (or one of the other flavors). If you try to pass a non-Referenceable object (say, by returning one from a remote_* method), you'll get an - InsecureJelly + InsecureJelly exception2.

    @@ -613,16 +613,16 @@ sort. The Twisted Way is the same.

    The only special thing you do is to define your Exception -subclass by deriving it from pb.Error. When any remotely-invokable method +subclass by deriving it from pb.Error. When any remotely-invokable method (like remote_* or perspective_*) raises a pb.Error-derived exception, a serialized form of that Exception object will be sent back over the wire4. The other side (which did callRemote) will have the errback -callback run with a Failure object that contains a copy of +callback run with a Failure object that contains a copy of the exception object. This Failure object can be queried to retrieve the error message and a stack traceback.

    -

    Failure is a +

    Failure is a special class, defined in twisted/python/failure.py, created to make it easier to handle asynchronous exceptions. Just as exception handlers can be nested, errback functions can be chained. If one errback @@ -790,7 +790,7 @@ traffic), but it will print out an unsightly stack trace on the server's stderr with a message that says Peer Will Receive PB Traceback, just as if the exception had happened outside a remotely-invokable method. (This -message will go the current log target, if log.startLogging was used to redirect it). The +message will go the current log target, if log.startLogging was used to redirect it). The client will get the same Failure object in either case, but subclassing your exception from pb.Error is the way to tell Twisted that you expect this sort of exception, and that it is ok to just @@ -799,7 +799,7 @@ instead of broken() to see the change in the server's behavior.

    -

    If you don't add an errback function to the Deferred, then a remote +

    If you don't add an errback function to the Deferred, then a remote exception will still send a Failure object back over, but it will get lodged in the Deferred with nowhere to go. When that Deferred finally goes out of scope, the side that did @@ -808,9 +808,9 @@ that point (after all, the callRemote that triggered the problem is long gone), but it will emit a traceback. So be a good programmer and always add errback handlers, even if they are just -calls to log.err.

    +calls to log.err.

    -

    Try/Except blocks and Failure.trap

    +

    Try/Except blocks and Failure.trap

    To implement the equivalent of the Python try/except blocks (which can trap particular kinds of exceptions and pass others up to @@ -1063,7 +1063,7 @@

    In this example, callTwo tries to send an instance of a locally-defined class through callRemote. The default security -model implemented by jelly +model implemented by jelly on the remote end will not allow unknown classes to be unserialized (i.e. taken off the wire as a stream of bytes and turned back into an object: a living, breathing instance of some class): one reason is that it does not @@ -1071,7 +1071,7 @@ corresponds to the remote object5.

    The receiving end of the connection gets to decide what to accept and what -to reject. It indicates its disapproval by raising a jelly.InsecureJelly exception. Because it occurs +to reject. It indicates its disapproval by raising a jelly.InsecureJelly exception. Because it occurs at the remote end, the exception is returned to the caller asynchronously, so an errback handler for the associated Deferred is run. That errback receives a Failure which wraps the @@ -1086,7 +1086,7 @@ trap, and it will return the matching member. In this case, the kinds of exceptions we are checking for (MyException and MyOtherException) may be raised by the remote end: they inherit -from pb.Error.

    +from pb.Error.

    The handler can return None to terminate processing of the errback chain (to be precise, it switches to the callback that follows the @@ -1099,19 +1099,19 @@ importance in an asynchronous environment is that an exception that falls off the end of the Deferred will not be signalled until that Deferred goes out of scope, and at that point may only cause a -log message (which could even be thrown away if log.startLogging is not used to point it at +log message (which could even be thrown away if log.startLogging is not used to point it at stdout or a log file). In contrast, a synchronous exception that is not handled by any other except: block will very visibly terminate the program immediately with a noisy stack trace.

    callFour shows another kind of exception that can occur -while using callRemote: pb.DeadReferenceError. This one occurs when the +while using callRemote: pb.DeadReferenceError. This one occurs when the remote end has disconnected or crashed, leaving the local side with a stale reference. This kind of exception happens to be reported right away (XXX: is this guaranteed? probably not), so must be caught in a traditional synchronous try: except pb.DeadReferenceError block.

    -

    Yet another kind that can occur is a pb.PBConnectionLost exception. This occurs +

    Yet another kind that can occur is a pb.PBConnectionLost exception. This occurs (asynchronously) if the connection was lost while you were waiting for a callRemote call to complete. When the line goes dead, all pending requests are terminated with this exception. Note that you have no @@ -1142,15 +1142,15 @@ or even more powerful classes that you have available in your server program). Allowing a remote entity to create arbitrary classes in your namespace is nearly equivalent to allowing them to run arbitrary code.

    -

    The InsecureJelly +

    The InsecureJelly exception arises because the class being sent over the wire has not been -registered with the serialization layer (known as jelly). The easiest way to make it possible to -copy entire class instances over the wire is to have them inherit from pb.Copyable, and then to use +registered with the serialization layer (known as jelly). The easiest way to make it possible to +copy entire class instances over the wire is to have them inherit from pb.Copyable, and then to use setUnjellyableForClass(remoteClass, localClass) on the receiving side. See Passing Complex Types for an example.

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/pb.html twisted-12.2.0/doc/howto/pb.html --- twisted-12.0.0/doc/howto/pb.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/pb.html 2012-08-31 12:37:47.000000000 +0000 @@ -47,6 +47,6 @@ the protocol is completely symmetrical.

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/plugin.html twisted-12.2.0/doc/howto/plugin.html --- twisted-12.0.0/doc/howto/plugin.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/plugin.html 2012-08-31 12:37:44.000000000 +0000 @@ -16,7 +16,7 @@ extensibility is achieved through the definition of one or more APIs and a mechanism for collecting code plugins which implement this API to provide some additional functionality. - At the base of this system is the twisted.plugin module.

    + At the base of this system is the twisted.plugin module.

    Making an application extensible using the plugin system has several strong advantages over other techniques:

    @@ -35,7 +35,7 @@

    Writing Extensible Programs

    -

    Taking advantage of twisted.plugin is +

    Taking advantage of twisted.plugin is a two step process:

      @@ -57,7 +57,7 @@
    1. - At one or more places in your program, invoke twisted.plugin.getPlugins and iterate over its + At one or more places in your program, invoke twisted.plugin.getPlugins and iterate over its result.
    @@ -193,7 +193,7 @@

    steelPlate and brassPlate now provide both - IPlugin and IMaterial. + IPlugin and IMaterial. All that remains is to make this module available at an appropriate location. For this, there are two options. The first of these is primarily useful during development: if a directory which @@ -215,7 +215,7 @@

    Alternate Plugin Packages

    -

    getPlugins takes one +

    getPlugins takes one additional argument not mentioned above. If passed in, the 2nd argument should be a module or package to be used instead of twisted.plugins as the plugin meta-package. If you @@ -289,6 +289,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/process.html twisted-12.2.0/doc/howto/process.html --- twisted-12.0.0/doc/howto/process.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/process.html 2012-08-31 12:37:44.000000000 +0000 @@ -16,9 +16,9 @@ connects to local processes with much the same API. The API is described in more detail in the documentation of:

    @@ -53,7 +53,7 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/quotes.html twisted-12.2.0/doc/howto/quotes.html --- twisted-12.0.0/doc/howto/quotes.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/quotes.html 2012-08-31 12:37:43.000000000 +0000 @@ -209,6 +209,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/rdbms.html twisted-12.2.0/doc/howto/rdbms.html --- twisted-12.0.0/doc/howto/rdbms.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/rdbms.html 2012-08-31 12:37:45.000000000 +0000 @@ -14,7 +14,7 @@

    Twisted is an asynchronous networking framework, but most database API implementations unfortunately have blocking - interfaces -- for this reason, twisted.enterprise.adbapi was created. It is + interfaces -- for this reason, twisted.enterprise.adbapi was created. It is a non-blocking interface to the standardized DB-API 2.0 API, which allows you to access a number of different RDBMSes.

    @@ -59,11 +59,11 @@

    Those delays are unacceptable when using an asynchronous framework such as Twisted. For this reason, twisted provides - twisted.enterprise.adbapi, an + twisted.enterprise.adbapi, an asynchronous wrapper for any DB-API 2.0-compliant module.

    -

    enterprise.adbapi will do +

    enterprise.adbapi will do blocking database operations in separate threads, which trigger callbacks in the originating thread when they complete. In the @@ -73,9 +73,9 @@

    How do I use adbapi?

    Rather than creating a database connection directly, use the - adbapi.ConnectionPool + adbapi.ConnectionPool class to manage - a connections for you. This allows enterprise.adbapi to use multiple + a connections for you. This allows enterprise.adbapi to use multiple connections, one per thread. This is easy:

    1 2 @@ -89,10 +89,10 @@

    @@ -123,13 +123,13 @@

    This is straightforward, except perhaps for the return value - of getAge. It returns a twisted.internet.defer.Deferred, which allows + of getAge. It returns a twisted.internet.defer.Deferred, which allows arbitrary callbacks to be called upon completion (or upon failure). More documentation on Deferred is available here.

    In addition to runQuery, there is also runOperation, and runInteraction that gets called with a callable (e.g. a function). - The function will be called in the thread with a twisted.enterprise.adbapi.Transaction, + The function will be called in the thread with a twisted.enterprise.adbapi.Transaction, which basically mimics a DB-API cursor. In all cases a database transaction will be commited after your database usage is finished, unless an exception is raised in which case it will be rolled back.

    @@ -223,6 +223,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/reactor-basics.html twisted-12.2.0/doc/howto/reactor-basics.html --- twisted-12.0.0/doc/howto/reactor-basics.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/reactor-basics.html 2012-08-31 12:37:43.000000000 +0000 @@ -48,7 +48,7 @@

    - Twisted applications can use the interfaces in twisted.application.service to configure and run the + Twisted applications can use the interfaces in twisted.application.service to configure and run the application instead of using boilerplate reactor code. See Using Application for an introduction to Application. @@ -56,7 +56,7 @@

    Using the reactor object

    -

    You can get to the reactor object using the following code:

    +

    You can get to the reactor object using the following code:

    1

    from twisted.internet import reactor @@ -67,26 +67,27 @@ the interfaces may not be implemented:

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/sendmsg.html twisted-12.2.0/doc/howto/sendmsg.html --- twisted-12.0.0/doc/howto/sendmsg.html 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/doc/howto/sendmsg.html 2012-08-31 12:37:44.000000000 +0000 @@ -0,0 +1,221 @@ + + +Twisted Documentation: Extremely Low-Level Socket Operations + + + + +

    Extremely Low-Level Socket Operations

    + +
    + + +

    Introduction

    + +

    + Beyond supporting streams of data (SOCK_STREAM) or datagrams (SOCK_DGRAM), + POSIX sockets have additional features not accessible via send(2) and + recv(2). These features include things like scatter/gather I/O, + duplicating file descriptors into other processes, and accessing + out-of-band data. +

    + +

    + Twisted includes a wrapper around the two C APIs which make these things + possible, + sendmsg + and + recvmsg. + This document covers their usage. It is intended for Twisted maintainers. + Application developers looking for this functionality should look for the + high-level APIs Twisted provides on top of these wrappers. +

    + +

    sendmsg

    + +

    + sendmsg(2) exposes nearly all sender-side functionality of a + socket. For a SOCK_STREAM socket, it can send bytes that become part of + the stream of data being carried over the connection. For a SOCK_DGRAM + socket, it can send bytes that become datagrams sent from the socket. It + can send data from multiple memory locations (gather I/O). Over AF_UNIX + sockets, it can copy file descriptors into whichever process is receiving + on the other side. The wrapper included in Twisted, + send1msg, exposes + many (but not all) of these features. This document covers the usage of + the features it does expose. The alternate spelling for the wrapper is + used to indicate the primary limitation, which is it that the interface + supports sending only one iovec at a time. +

    + +

    recvmsg

    + +

    + Likewise, recvmsg(2) exposes nearly all the receiver-side + functionality of a socket. It can receive stream data over from a + SOCK_STREAM socket or datagrams from a SOCK_DGRAM socket. It can receive + that data into multiple memory locations (scatter I/O), and it can receive + those copied file descriptors. The wrapper included in + Twisted, recv1msg, + exposes many (but not all) of these features. This document covers the + usage of the features it does expose. The alternate spelling for the + wrapper is used to indicate the primary limitation, which is that the + interface supports receiving only one iovec at a time. +

    + +

    Sending And Receiving Regular Data

    + +

    + sendmsg can be used in a way which makes it equivalent to using the send + call. The first argument to sendmsg is (in this case and all others) a + file descriptor over which to send the data. The second argument is a + string giving the data to send. +

    + +

    + On the other end, recvmsg can be used to replace a recv call. The first + argument to recvmsg is (again, in all cases) a file descriptor over which + to receive the data. The second argument is an integer giving the maximum + number of data to receive. +

    + +
    + +

    Copying File Descriptors

    + +

    + Used with an AF_UNIX socket, sendmsg send a copy of a file descriptor into + whatever process is receiving on the other end of the socket. This is + done using the ancillary data argument. Ancillary data consists of a list + of three-tuples. A three-tuple constructed with SOL_SOCKET, SCM_RIGHTS, + and a platform-endian packed file descriptor number will copy that file + descriptor. +

    + +

    + File descriptors copied this way must be received using a recvmsg call. + No special arguments are required to receive these descriptors. They will + appear, encoded as a native-order string, in the ancillary data list + returned by recvmsg. +

    + +
    + +
    + +

    Index

    + Version: 12.2.0 + + \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/servers.html twisted-12.2.0/doc/howto/servers.html --- twisted-12.0.0/doc/howto/servers.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/servers.html 2012-08-31 12:37:44.000000000 +0000 @@ -17,7 +17,7 @@ code can be reused for SSL and Unix socket servers). There is a separate document covering UDP.

    -

    Your protocol handling class will usually subclass twisted.internet.protocol.Protocol. Most +

    Your protocol handling class will usually subclass twisted.internet.protocol.Protocol. Most protocol handlers inherit either from this class or from one of its convenience children. An instance of the protocol class is instantiated per-connection, on demand, and will go @@ -27,7 +27,7 @@

    The persistent configuration is kept in a Factory class, which usually inherits - from twisted.internet.protocol.Factory. The buildProtocol + from twisted.internet.protocol.Factory. The buildProtocol method of the Factory is used to create a Protocol for each new connection.

    @@ -37,7 +37,7 @@ fact does not know anything about the network. See the endpoints documentation for more information, - or twisted.internet.interfaces.IReactorTCP.listenTCP, + or twisted.internet.interfaces.IReactorTCP.listenTCP, and the other IReactor*.listen* APIs for the lower level APIs that endpoints are based on.

    @@ -516,7 +516,7 @@
    Source listing - listings/servers/chat.py

    The only API you might not be familiar with - is listenTCP. listenTCP is + is listenTCP. listenTCP is the method which connects a Factory to the network. This is the lower-level API that endpoints wraps for you.

    @@ -543,6 +543,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/ssl.html twisted-12.2.0/doc/howto/ssl.html --- twisted-12.0.0/doc/howto/ssl.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/ssl.html 2012-08-31 12:37:44.000000000 +0000 @@ -32,21 +32,21 @@ key file name, and certificate file name.

    Instead of using listenTCP and connectTCP to create a connection, use - listenSSL and - connectSSL for a + listenSSL and + connectSSL for a server and client respectively. These methods take a contextFactory as an additional argument.

    The basic server context factory is - twisted.internet.ssl.ContextFactory, and the basic + twisted.internet.ssl.ContextFactory, and the basic client context factory is - twisted.internet.ssl.ClientContextFactory. They can + twisted.internet.ssl.ClientContextFactory. They can be used as-is or subclassed. - twisted.internet.ssl.DefaultOpenSSLContextFactory + twisted.internet.ssl.DefaultOpenSSLContextFactory is a convenience server class that subclasses ContextFactory and adds default parameters to the SSL handshake and connection. Another useful class is - twisted.internet.ssl.CertificateOptions; it is a + twisted.internet.ssl.CertificateOptions; it is a factory for SSL context objects that lets you specify many of the common verification and session options so it can do the proper pyOpenSSL initialization for you.

    @@ -168,12 +168,12 @@ is explicitly disallowed in both DefaultOpenSSLContextFactory and ClientContextFactory for being insecure by calling set_options(SSL.OP_NO_SSLv2) on their contexts. See - twisted.internet.ssl for additional comments.

    + twisted.internet.ssl for additional comments.

    Using startTLS

    If you want to switch from unencrypted to encrypted traffic - mid-connection, you'll need to turn on SSL with startTLS on both + mid-connection, you'll need to turn on SSL with startTLS on both ends of the connection at the same time via some agreed-upon signal like the reception of a particular message. You can readily verify the switch to an encrypted channel by examining the packet payloads with a tool like @@ -526,10 +526,10 @@

    Other facilities

    -

    twisted.protocols.amp supports encrypted +

    twisted.protocols.amp supports encrypted connections and exposes a startTLS method one can use or - subclass. twisted.web has built-in SSL support in - its client, http, and xmlrpc modules.

    + subclass. twisted.web has built-in SSL support in + its client, http, and xmlrpc modules.

    Conclusion

    @@ -545,6 +545,6 @@

    Index

    - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tap.html twisted-12.2.0/doc/howto/tap.html --- twisted-12.0.0/doc/howto/tap.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/tap.html 2012-08-31 12:37:47.000000000 +0000 @@ -21,7 +21,7 @@

    There are a few prerequisites to understanding this document:

    • A basic understanding of the Twisted Plugin System (i.e., - the twisted.plugin module) is + the twisted.plugin module) is necessary, however, step-by-step instructions will be given. Reading The Twisted Plugin System is recommended, in particular the Extending an @@ -81,15 +81,15 @@

      In this file, define an object which provides the interfaces - twisted.plugin.IPlugin - and twisted.application.service.IServiceMaker. + twisted.plugin.IPlugin + and twisted.application.service.IServiceMaker.

      The tapname attribute of your IServiceMaker provider will be used as the subcommand name in a command like twistd [subcommand] [args...], and the options attribute (which should be -a usage.Options +a usage.Options subclass) will be used to parse the given args.

      1 @@ -181,7 +181,7 @@ If you are building a twistd plugin and you want to support a wide variety of authentication patterns, Twisted provides an easy-to-use mixin for your Options subclass: - strcred.AuthOptionMixin. + strcred.AuthOptionMixin. The following code is an example of using this mixin:

      @@ -296,7 +296,7 @@

      - For a full list of cred plugins supported, see twisted.plugins, or use the command-line help: + For a full list of cred plugins supported, see twisted.plugins, or use the command-line help:

      @@ -318,6 +318,6 @@
       
       
           

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/testing.html twisted-12.2.0/doc/howto/testing.html --- twisted-12.0.0/doc/howto/testing.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/testing.html 2012-08-31 12:37:45.000000000 +0000 @@ -39,7 +39,7 @@ created if two instances of Trial are run in parallel from the same directory, so as to avoid giving two different test-runs the same temporary directory.

      -

      The twisted.python.lockfile utility is used to lock +

      The twisted.python.lockfile utility is used to lock the _trial_temp directories. On Linux, this results in symlinks to pids. On Windows, directories are created with a single file with a pid as the contents. These lock files will be cleaned up if Trial exits normally @@ -73,7 +73,7 @@ always run regardless of whether your test passes or fails (like a finally clause in a try-except-finally construct). Exceptions in tearDown are flagged as errors and flunk the test. - TestCase.addCleanup is + TestCase.addCleanup is another useful tool for cleaning up. With it, you can register callables to clean up resources as the test allocates them. Generally, code should be written so that only resources allocated in the tests need to be cleaned up in @@ -86,21 +86,21 @@ Deferred has triggered and its callbacks have been run. Don't use reactor.run(), reactor.stop(), reactor.crash() or reactor.iterate() in your tests.

      -

      Calls to reactor.callLater create IDelayedCalls. These need to be run +

      Calls to reactor.callLater create IDelayedCalls. These need to be run or cancelled during a test, otherwise they will outlive the test. This would be bad, because they could interfere with a later test, causing confusing failures in unrelated tests! For this reason, Trial checks the reactor to make -sure there are no leftover IDelayedCalls in the reactor after a +sure there are no leftover IDelayedCalls in the reactor after a test, and will fail the test if there are. The cleanest and simplest way to make sure this all works is to return a Deferred from your test.

      Similarly, sockets created during a test should be closed by the end of the test. This applies to both listening ports and client connections. So, calls to reactor.listenTCP (and listenUNIX, and so on) -return IListeningPorts, and these should be -cleaned up before a test ends by calling their stopListening method. -Calls to reactor.connectTCP return IConnectors, which should be cleaned -up by calling their disconnect method. Trial +return IListeningPorts, and these should be +cleaned up before a test ends by calling their stopListening method. +Calls to reactor.connectTCP return IConnectors, which should be cleaned +up by calling their disconnect method. Trial will warn about unclosed sockets.

      The golden rule is: If your tests call a function which returns a Deferred, @@ -130,7 +130,7 @@ be written test-driven, just as any other code would be. It also improves the way in which warnings reporting when a test suite is running.

      -

      TestCase.flushWarnings +

      TestCase.flushWarnings allows tests to be written which make assertions about what warnings have been emitted during a particular test method. In order to test a warning with flushWarnings, write a test which first invokes the code which @@ -162,6 +162,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/threading.html twisted-12.2.0/doc/howto/threading.html --- twisted-12.0.0/doc/howto/threading.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/threading.html 2012-08-31 12:37:43.000000000 +0000 @@ -15,7 +15,7 @@

      Most code in Twisted is not thread-safe. For example, writing data to a transport from a protocol is not thread-safe. Therefore, we want a way to schedule methods to be run in the - main event loop. This can be done using the function twisted.internet.interfaces.IReactorThreads.callFromThread:

      + main event loop. This can be done using the function twisted.internet.interfaces.IReactorThreads.callFromThread:

      1 2 3 @@ -44,8 +44,8 @@

      Sometimes we may want to run methods in threads - for example, in order to access blocking APIs. Twisted provides - methods for doing so using the IReactorThreads API (twisted.internet.interfaces.IReactorThreads). - Additional utility functions are provided in twisted.internet.threads. Basically, these + methods for doing so using the IReactorThreads API (twisted.internet.interfaces.IReactorThreads). + Additional utility functions are provided in twisted.internet.threads. Basically, these methods allow us to queue methods to be run by a thread pool.

      @@ -74,8 +74,8 @@

      Utility Methods

      -

      The utility methods are not part of the twisted.internet.reactor APIs, but are implemented - in twisted.internet.threads.

      +

      The utility methods are not part of the twisted.internet.reactor APIs, but are implemented + in twisted.internet.threads.

      If we have multiple methods to run sequentially within a thread, we can do:

      @@ -143,7 +143,7 @@

      If you wish to call a method in the reactor thread and get its result, - you can use blockingCallFromThread:

      + you can use blockingCallFromThread:

      1 2 @@ -187,7 +187,7 @@

      Managing the Thread Pool

      -

      The thread pool is implemented by twisted.python.threadpool.ThreadPool.

      +

      The thread pool is implemented by twisted.python.threadpool.ThreadPool.

      We may want to modify the size of the threadpool, increasing or decreasing the number of threads in use. We can do this @@ -208,6 +208,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/time.html twisted-12.2.0/doc/howto/time.html --- twisted-12.0.0/doc/howto/time.html 2012-02-10 16:32:41.000000000 +0000 +++ twisted-12.2.0/doc/howto/time.html 2012-08-31 12:37:43.000000000 +0000 @@ -11,7 +11,7 @@

      Let's say we want to run a task X seconds in the future. - The way to do that is defined in the reactor interface twisted.internet.interfaces.IReactorTime:

      + The way to do that is defined in the reactor interface twisted.internet.interfaces.IReactorTime:

      1 2 3 @@ -33,8 +33,8 @@

      If the result of the function is important or if it may be necessary - to handle exceptions it raises, then the twisted.internet.task.deferLater utility conveniently - takes care of creating a Deferred and setting up a delayed + to handle exceptions it raises, then the twisted.internet.task.deferLater utility conveniently + takes care of creating a Deferred and setting up a delayed call:

      1 2 @@ -65,7 +65,7 @@

      If we want a task to run every X seconds repeatedly, we can - use twisted.internet.task.LoopingCall:

      + use twisted.internet.task.LoopingCall:

      1 2 3 @@ -113,6 +113,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/trial.html twisted-12.2.0/doc/howto/trial.html --- twisted-12.0.0/doc/howto/trial.html 2012-02-10 16:32:42.000000000 +0000 +++ twisted-12.2.0/doc/howto/trial.html 2012-08-31 12:37:47.000000000 +0000 @@ -6,7 +6,7 @@

      Test-driven development with Twisted

      - +
      @@ -22,8 +22,8 @@ Most Twisted code is tested using TDD.

      To gain a solid understanding of unit testing in Python, you should read -the unittest -- -Unit testing framework chapter of the Python Library +the unittest -- +Unit testing framework chapter of the Python Library Reference. There is also a ton of information available online and in books.

      @@ -652,7 +652,7 @@ try: return map(int, args) except ValueError: - raise TypeError("Coudln't coerce arguments to integers: %s" % args) + raise TypeError("Couldn't coerce arguments to integers: %s" % args) def add(self, a, b): a, b = self._make_ints(a, b) @@ -685,7 +685,7 @@

      Up to this point we've been doing fairly standard Python unit testing. With only a few cosmetic changes (most importantly, directly importing - unittest instead of using Twisted's unittest version) we could make the + unittest instead of using Twisted's unittest version) we could make the above tests run using Python's standard library unit testing framework.

      Here we will assume a basic familiarity with Twisted's network I/O, timing, @@ -786,11 +786,9 @@ calculus/remote_1.py below. We call buildProtocol to ask the factory to build us a protocol object that knows how to talk to our server. We then make a fake -network transport, an instance of -StringTransport class (note that test packages are generally not part of -Twisted's public API; proto_helpers is an exception). This fake +network transport, an instance of twisted.test.proto_helpers.StringTransport +class (note that test packages are generally not part of Twisted's public API; +twisted.test.proto_helpers is an exception). This fake transport is the key to the communications. It is used to emulate a network connection without a network. The address and port passed to buildProtocol are typically used by the factory to choose to immediately deny remote connections; since we're using a fake transport, we can choose any value that will be acceptable to the factory. In this case the factory just ignores the address, so we don't need to pick anything in particular.

      @@ -916,7 +914,7 @@ main()
      -

      As mentioned, this server creates a protocol that inherits from basic.LineReceiver, and then a +

      As mentioned, this server creates a protocol that inherits from basic.LineReceiver, and then a factory that uses it as protocol. The only trick is the CalculationProxy object, which calls Calculation methods through remote_* methods. This pattern is used frequently in Twisted, because it is very explicit about what methods you are making accessible.

      @@ -1120,11 +1118,11 @@
      -

      More good pratices

      +

      More good practices

      Testing scheduling

      -

      When testing code that involves the passage of time, waiting e.g. for a two hour timeout to occur in a test is not very realistic. Twisted provides a solution to this, the Clock class that allows one to simulate the passage of time.

      +

      When testing code that involves the passage of time, waiting e.g. for a two hour timeout to occur in a test is not very realistic. Twisted provides a solution to this, the Clock class that allows one to simulate the passage of time.

      As an example we'll test the code for client request timeout: since our client uses TCP it can hang for a long time (firewall, connectivity problems, etc...). @@ -2039,6 +2037,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/backends.html twisted-12.2.0/doc/howto/tutorial/backends.html --- twisted-12.0.0/doc/howto/tutorial/backends.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/backends.html 2012-08-31 12:37:49.000000000 +0000 @@ -1343,6 +1343,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/client.html twisted-12.2.0/doc/howto/tutorial/client.html --- twisted-12.0.0/doc/howto/tutorial/client.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/client.html 2012-08-31 12:37:49.000000000 +0000 @@ -255,6 +255,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/components.html twisted-12.2.0/doc/howto/tutorial/components.html --- twisted-12.0.0/doc/howto/tutorial/components.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/components.html 2012-08-31 12:37:50.000000000 +0000 @@ -1127,6 +1127,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/configuration.html twisted-12.2.0/doc/howto/tutorial/configuration.html --- twisted-12.0.0/doc/howto/tutorial/configuration.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/configuration.html 2012-08-31 12:37:48.000000000 +0000 @@ -823,7 +823,7 @@ twisted/plugins/finger_tutorial.py - listings/finger/twisted/plugins/finger_tutorial.py -

      Note that the second argument to ServiceMaker, +

      Note that the second argument to ServiceMaker, finger.tap, is a reference to a module (finger/tap.py), not to a filename.

      @@ -865,6 +865,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/factory.html twisted-12.2.0/doc/howto/tutorial/factory.html --- twisted-12.0.0/doc/howto/tutorial/factory.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/factory.html 2012-08-31 12:37:49.000000000 +0000 @@ -708,6 +708,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/index.html twisted-12.2.0/doc/howto/tutorial/index.html --- twisted-12.0.0/doc/howto/tutorial/index.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/index.html 2012-08-31 12:37:48.000000000 +0000 @@ -78,6 +78,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/intro.html twisted-12.2.0/doc/howto/tutorial/intro.html --- twisted-12.0.0/doc/howto/tutorial/intro.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/intro.html 2012-08-31 12:37:48.000000000 +0000 @@ -75,7 +75,7 @@

      The Reactor

      -

      You don't call Twisted, Twisted calls you. The reactor is Twisted's main event loop, similar to +

      You don't call Twisted, Twisted calls you. The reactor is Twisted's main event loop, similar to the main loop in other toolkits available in Python (Qt, wx, and Gtk). There is exactly one reactor in any running Twisted application. Once started it loops over and over again, responding to network events and making scheduled calls to @@ -189,7 +189,7 @@ reactor.run()

      -

      Here we make FingerProtocol inherit from LineReceiver, so that we get data-based +

      Here we make FingerProtocol inherit from LineReceiver, so that we get data-based events on a line-by-line basis. We respond to the event of receiving the line with shutting down the connection.

      @@ -708,8 +708,8 @@ the protocol or the factory. Any services (such as TCPServer) which have the application as their parent will be started when the application is started by twistd. The application object is more -useful for returning an object that supports the IService, IServiceCollection, IProcess, -and sob.IPersistable +useful for returning an object that supports the IService, IServiceCollection, IProcess, +and sob.IPersistable interfaces with the given parameters; we'll be seeing these in the next part of the tutorial. As the parent of the TCPServer we opened, the application lets us manage the TCPServer.

      @@ -720,6 +720,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/library.html twisted-12.2.0/doc/howto/tutorial/library.html --- twisted-12.0.0/doc/howto/tutorial/library.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/library.html 2012-08-31 12:37:49.000000000 +0000 @@ -266,6 +266,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/pb.html twisted-12.2.0/doc/howto/tutorial/pb.html --- twisted-12.0.0/doc/howto/tutorial/pb.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/pb.html 2012-08-31 12:37:50.000000000 +0000 @@ -723,6 +723,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/protocol.html twisted-12.2.0/doc/howto/tutorial/protocol.html --- twisted-12.0.0/doc/howto/tutorial/protocol.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/protocol.html 2012-08-31 12:37:50.000000000 +0000 @@ -20,7 +20,7 @@ service to send those announcements on the web, on IRC and over XML-RPC. Resources and XML-RPC are introduced in the Web Applications portion of the Twisted Web howto. More examples -using twisted.words.protocols.irc can be found +using twisted.words.protocols.irc can be found in Writing a TCP Client and the Twisted Words examples.

      @@ -154,9 +154,9 @@

      This program has two protocol-factory-TCPServer pairs, which are both child services of the application. Specifically, -the setServiceParent +the setServiceParent method is used to define the two TCPServer services as children -of application, which implements IServiceCollection. Both +of application, which implements IServiceCollection. Both services are thus started with the application.

      @@ -196,7 +196,7 @@ none of our protocol classes had to be changed, and neither will have to change until the end of the tutorial.

      -

      As an application service, this new finger service implements the IService interface and +

      As an application service, this new finger service implements the IService interface and can be started and stopped in a standardized manner. We'll make use of this in the next example.

      @@ -320,7 +320,7 @@ ).setServiceParent(serviceCollection) -

      Most application services will want to use the Service base class, which implements +

      Most application services will want to use the Service base class, which implements all the generic IService behavior.

      Read Status File

      @@ -453,8 +453,8 @@ every 30 seconds), there is no FingerSetterFactory and thus nothing listening on port 1079.

      -

      Here we override the standard startService -and stopService hooks in +

      Here we override the standard startService +and stopService hooks in the Finger service, which is set up as a child service of the application in the last line of the code. startService calls _read, the function responsible for reading the @@ -1116,6 +1116,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/style.html twisted-12.2.0/doc/howto/tutorial/style.html --- twisted-12.0.0/doc/howto/tutorial/style.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/style.html 2012-08-31 12:37:49.000000000 +0000 @@ -328,6 +328,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/tutorial/web.html twisted-12.2.0/doc/howto/tutorial/web.html --- twisted-12.0.0/doc/howto/tutorial/web.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/howto/tutorial/web.html 2012-08-31 12:37:48.000000000 +0000 @@ -16,7 +16,7 @@

      This is the sixth part of the Twisted tutorial Twisted from Scratch, or The Evolution of Finger.

      In this part, we demonstrate adding a web frontend using -simple twisted.web.resource.Resource +simple twisted.web.resource.Resource objects: UserStatusTree, which will produce a listing of all users at the base URL (/) of our site; UserStatus, which gives the status @@ -605,6 +605,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/udp.html twisted-12.2.0/doc/howto/udp.html --- twisted-12.0.0/doc/howto/udp.html 2012-02-10 16:32:43.000000000 +0000 +++ twisted-12.2.0/doc/howto/udp.html 2012-08-31 12:37:46.000000000 +0000 @@ -20,14 +20,14 @@

      Since there are no connections, we only use a single object, a protocol, for each UDP socket. We then use the reactor to connect this protocol to a UDP transport, using the - twisted.internet.interfaces.IReactorUDP + twisted.internet.interfaces.IReactorUDP reactor API.

      DatagramProtocol

      The class where you actually implement the protocol parsing and handling will usually be descended - from twisted.internet.protocol.DatagramProtocol or + from twisted.internet.protocol.DatagramProtocol or from one of its convenience children. The DatagramProtocol class receives datagrams and can send them out over the network. Received datagrams include the address they were sent from. When sending datagrams @@ -60,15 +60,15 @@

      As you can see, the protocol is registered with the reactor. This means it may be persisted if it's added to an application, and thus it has - startProtocol - and stopProtocol + startProtocol + and stopProtocol methods that will get called when the protocol is connected and disconnected from a UDP socket.

      The protocol's transport attribute will - implement the twisted.internet.interfaces.IUDPTransport interface. + implement the twisted.internet.interfaces.IUDPTransport interface. Notice that the host argument should be an - IP address, not a hostname. If you only have the hostname use reactor.resolve() to resolve the address (see twisted.internet.interfaces.IReactorCore.resolve).

      + IP address, not a hostname. If you only have the hostname use reactor.resolve() to resolve the address (see twisted.internet.interfaces.IReactorCore.resolve).

      Connected UDP

      @@ -235,10 +235,10 @@

      As with UDP, with multicast there is no server/client differentiation at the protocol level. Our server example is very simple and closely - resembles a normal listenUDP + resembles a normal listenUDP protocol implementation. The main difference is that instead - of listenUDP, listenMulticast - is called with the port number. The server calls joinGroup to + of listenUDP, listenMulticast + is called with the port number. The server calls joinGroup to join a multicast group. A DatagramProtocol that is listening with multicast and has joined a group can receive multicast datagrams, but also unicast datagrams sent directly to its @@ -289,16 +289,16 @@

      Note that a multicast socket will have a default TTL (time to live) of 1. That is, datagrams won't traverse more than one router hop, unless a higher TTL is set with - setTTL. Other + setTTL. Other functionality provided by the multicast transport - includes setOutgoingInterface - and setLoopbackMode - -- see IMulticastTransport for more + includes setOutgoingInterface + and setLoopbackMode + -- see IMulticastTransport for more information.

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/vision.html twisted-12.2.0/doc/howto/vision.html --- twisted-12.0.0/doc/howto/vision.html 2012-02-10 16:32:44.000000000 +0000 +++ twisted-12.2.0/doc/howto/vision.html 2012-08-31 12:37:44.000000000 +0000 @@ -38,6 +38,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/howto/website-template.tpl twisted-12.2.0/doc/howto/website-template.tpl --- twisted-12.0.0/doc/howto/website-template.tpl 2011-11-20 15:23:17.000000000 +0000 +++ twisted-12.2.0/doc/howto/website-template.tpl 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ - - - - - -Twisted Documentation: - - - - -

      -
      -
      - -
      - -

      Index

      - - - diff -Nru twisted-12.0.0/doc/index.html twisted-12.2.0/doc/index.html --- twisted-12.0.0/doc/index.html 2012-02-10 16:32:41.000000000 +0000 +++ twisted-12.2.0/doc/index.html 2012-08-31 12:37:43.000000000 +0000 @@ -26,6 +26,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/man/manhole-man.html twisted-12.2.0/doc/man/manhole-man.html --- twisted-12.0.0/doc/man/manhole-man.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/man/manhole-man.html 2012-08-31 12:37:51.000000000 +0000 @@ -45,6 +45,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/man/pyhtmlizer-man.html twisted-12.2.0/doc/man/pyhtmlizer-man.html --- twisted-12.0.0/doc/man/pyhtmlizer-man.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/man/pyhtmlizer-man.html 2012-08-31 12:37:51.000000000 +0000 @@ -46,6 +46,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/man/tap2deb-man.html twisted-12.2.0/doc/man/tap2deb-man.html --- twisted-12.0.0/doc/man/tap2deb-man.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/man/tap2deb-man.html 2012-08-31 12:37:51.000000000 +0000 @@ -96,6 +96,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/man/tap2rpm-man.html twisted-12.2.0/doc/man/tap2rpm-man.html --- twisted-12.0.0/doc/man/tap2rpm-man.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/man/tap2rpm-man.html 2012-08-31 12:37:51.000000000 +0000 @@ -95,6 +95,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/man/tapconvert-man.html twisted-12.2.0/doc/man/tapconvert-man.html --- twisted-12.0.0/doc/man/tapconvert-man.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/man/tapconvert-man.html 2012-08-31 12:37:51.000000000 +0000 @@ -69,7 +69,7 @@

      COPYRIGHT

      -

      Copyright © 2000-2008 Twisted Matrix Laboratories. +

      Copyright © 2000-2012 Twisted Matrix Laboratories. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

      @@ -77,6 +77,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/man/tapconvert.1 twisted-12.2.0/doc/man/tapconvert.1 --- twisted-12.0.0/doc/man/tapconvert.1 2008-10-28 20:12:14.000000000 +0000 +++ twisted-12.2.0/doc/man/tapconvert.1 2012-02-19 20:39:01.000000000 +0000 @@ -34,7 +34,7 @@ .SH "REPORTING BUGS" To report a bug, visit \fIhttp://twistedmatrix.com/bugs/\fR .SH COPYRIGHT -Copyright \(co 2000-2008 Twisted Matrix Laboratories. +Copyright \(co 2000-2012 Twisted Matrix Laboratories. .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff -Nru twisted-12.0.0/doc/man/trial-man.html twisted-12.2.0/doc/man/trial-man.html --- twisted-12.0.0/doc/man/trial-man.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/man/trial-man.html 2012-08-31 12:37:51.000000000 +0000 @@ -270,6 +270,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/man/twistd-man.html twisted-12.2.0/doc/man/twistd-man.html --- twisted-12.0.0/doc/man/twistd-man.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/man/twistd-man.html 2012-08-31 12:37:51.000000000 +0000 @@ -182,6 +182,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/specifications/banana.html twisted-12.2.0/doc/specifications/banana.html --- twisted-12.0.0/doc/specifications/banana.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/specifications/banana.html 2012-08-31 12:37:51.000000000 +0000 @@ -194,6 +194,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/specifications/index.html twisted-12.2.0/doc/specifications/index.html --- twisted-12.0.0/doc/specifications/index.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/specifications/index.html 2012-08-31 12:37:51.000000000 +0000 @@ -16,6 +16,6 @@

      Index

      - Version: 12.0.0 + Version: 12.2.0 \ No newline at end of file diff -Nru twisted-12.0.0/doc/upgrades/2.0/components.html twisted-12.2.0/doc/upgrades/2.0/components.html --- twisted-12.0.0/doc/upgrades/2.0/components.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/upgrades/2.0/components.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ - - -Twisted Documentation: The Twisted Zope Interfaces FAQ - - - - -

      The Twisted Zope Interfaces FAQ

      - -
      - - - -

      Twisted components system in 2.0

      - -

      Twisted code's own use of the twisted.python.components package has been updated to use Zope Interfaces in -the 2.0 release.

      - -

      New code developed starting with the 2.0 release of Twisted Core should use Zope -Interfaces directly rather than using the twisted.python.components -package.

      - -

      FAQ

      - -

      Why did Twisted switch to Zope Interfaces?

      - -

      -The twisted.python.components package is a large amount of on-going -maintenance. Using the Zope Interface package also provides a greater level of -compatibility between Twisted interfaces and Zope interfaces. -

      - -

      Why did Twisted switch to Zope Interfaces rather than PyProtocols?

      - -

      -The Zope Interface package was chosen over PyProtocols because of its greater -conceptual similarity to twisted.python.components. -

      - -

      Will this affect my deployment?

      - -

      -No. Releases of Twisted Core will include Zope Interfaces. -

      - -

      How can I update my own code?

      - -

      -Classes written using twisted.python.components declare which interfaces they -implement in this style: -

      - - -class C: - __implements__ = IFoo, - - -

      -This should be changed to: -

      - - -class C: - zope.interface.implements(IFoo) - - -

      - -What about third party classes dependant on the old style of implements -declarations? - -

      - -

      -Use backwardsCompatImplements to fix this. -

      - - -twisted.python.components.backwardsCompatImplements(C) - - -

      What about using third party classes?

      - -

      -If you are using third party libraries that only declare __implements__, these -objects should be made compatible with fixClassImplements:

      - - -# import o where o is some third party library -from thirdparty.lib import o - -twisted.python.components.fixClassImplements(o.__class__) - - -

      -This will make sure that __implements__ declarations get converted to the new -style of implements declarations. -

      - -

      Acknowledgements

      - -

      This document is the work of Jason A. Mobarak, with contributions from Mary -Gardiner.

      - -
      - -

      Index

      - Version: 12.0.0 - - \ No newline at end of file diff -Nru twisted-12.0.0/doc/upgrades/2.0/index.html twisted-12.2.0/doc/upgrades/2.0/index.html --- twisted-12.0.0/doc/upgrades/2.0/index.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/upgrades/2.0/index.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ - - -Twisted Documentation: Upgrading to Twisted 2.0 - - - - -

      Upgrading to Twisted 2.0

      -
        -
        - - - -
        - -

        Index

        - Version: 12.0.0 - - \ No newline at end of file diff -Nru twisted-12.0.0/doc/upgrades/2.0/split.html twisted-12.2.0/doc/upgrades/2.0/split.html --- twisted-12.0.0/doc/upgrades/2.0/split.html 2012-02-10 16:32:46.000000000 +0000 +++ twisted-12.2.0/doc/upgrades/2.0/split.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,163 +0,0 @@ - - -Twisted Documentation: The Twisted Split FAQ - - - - -

        The Twisted Split FAQ

        - -
        - - - -

        What is the Twisted Split?

        - -

        -Twisted is very large. At last -count, it has around 80 thousand lines of code (yes, that is very -large for a Python project, maybe not so for a C++ project. ;). We broke it -into several smaller packages with the 2.0 release. -

        - -

        Why was Twisted being split?

        - -

        -The biggest reason was to make our release process more -agile. A regression in twisted.names, for example, could hold up the release -of the entire thing, when really it should only be holding up the release of -twisted.names. -

        - -

        -The other big reason is visibility. Twisted has a ton of -functionality, but many people miss out on it because they don't know -where it is hidden inside Twisted. The Twisted split gave every -sub-project its own web site and thus more visibility. -

        - -

        But I liked the monolithic packages. Can I still get them?

        - -

        -Yes. Tarball and Windows releases for Twisted and all of its -sub-projects will still be maintained. We encourage maintainers of -packages for OSes with automatic packaging systems to break up the -packages as well, so, for example, Debian will have -python2.3-twisted-core, python2.3-twisted-conch, -python2.3-twisted-names, and so on. -

        - -

        Where can I find information about the individual projects?

        - -

        -A list of Twisted -projects is available on the website. The list includes maintainer -information and links to project-specific pages with more detailed -information. -

        - -

        What are the new packages?

        - -

        -

          - -
        • Twisted - Core - This contains twisted.application, twisted.cred, - twisted.enterprise, twisted.internet, twisted.manhole, - twisted.persisted, twisted.protocols[1], twisted.python, twisted.spread, - twisted.trial
        • - -
        • Twisted - Conch - This contains twisted.conch.
        • - -
        • Twisted - Lore - This contains twisted.lore
        • - -
        • Twisted - Mail - This contains twisted.mail; NOTE the mail protocols - that were in twisted.protocols.(imap4,pop3,smtp) were moved to - twisted.mail.
        • - -
        • Twisted - Names - This contains twisted.names; NOTE - twisted.protocols.dns was moved to twisted.names.dns.
        • - -
        • Twisted - News - This contains twisted.news; NOTE - twisted.protocols.nntp was moved to twisted.news.nntp
        • - -
        • Twisted - Pair - This contains twisted.pair; NOTE ethernet, ip, raw, - and rawudp protocol support was moved from twisted.protocols to - twisted.pair. (deprecated)
        • - -
        • Twisted - Runner - This contains twisted.runner.
        • - -
        • Twisted - Web - This contains twisted.web; NOTE that - twisted.protocols.http was moved to twisted.web.http.
        • - -
        • Twisted - Words - This contains twisted.words; NOTE that twisted.im was - moved to twisted.words.im, twisted.xish was moved to - twisted.words.xish, AND the chat protocols (irc, msn, jabber, toc, - oscar) were moved to twisted.words.protocols.
        • -
        -

        - -

        [1]: twisted.protocols is very stripped -down now; it only includes the protocols that didn't belong anywhere -else. It still contains the simple protocols, the helper utilities, -and, ahem, FTP.

        - - -

        Will I have to rewrite my code? What API changes are there?

        - -

        -No existing code should break, however, many modules were -moved. Backwards compatibility support does exist in older versions of -Twisted, but was removed in Twisted 9.0.

        - -

        What about my deployments? What will I have to do to have the new packages?

        - -

        -It depends on your OS and how you installed Twisted originally. If -you're using Debian, we are planning on breaking up the Debian -packages to e.g. python2.3-twisted-core, python2.3-twisted-web, and so -on. If you're using Windows, or generally install Twisted from the -tarball or from an SVN checkout, monolithic options will still be -available. -

        - -

        -If you try to run code that imports a sub-package when that -sub-package is not available on the system, an ImportError will be -raised directing the user to the web site for that particular -sub-project. -

        - -

        Why are all the packages still named twisted.subproject?

        - -

        -This is controversial. While this does mean that there is a -mashed-together namespace under twisted., it's also the -simplest thing to do, and means less breakage for user-code, so we did that. -

        - -

        What does this mean for existing Twisted developers?

        - -

        -Not much. The repository is rearranged a bit; protocols have been -moved to their relevant packages and documentation is now stored in -doc/subproject/ instead of everything at the top-level of -doc/. Everything is still in the same repository and everyone still -has the same access levels they used to. -

        - -
        - -

        Index

        - Version: 12.0.0 - - \ No newline at end of file diff -Nru twisted-12.0.0/doc/upgrades/index.html twisted-12.2.0/doc/upgrades/index.html --- twisted-12.0.0/doc/upgrades/index.html 2012-02-10 16:32:45.000000000 +0000 +++ twisted-12.2.0/doc/upgrades/index.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ - - -Twisted Documentation: Upgrading - - - - -

        Upgrading

        - - - -

        Index

        - Version: 12.0.0 - - \ No newline at end of file diff -Nru twisted-12.0.0/setup.py twisted-12.2.0/setup.py --- twisted-12.0.0/setup.py 2011-11-20 15:19:42.000000000 +0000 +++ twisted-12.2.0/setup.py 2012-08-03 09:39:21.000000000 +0000 @@ -9,8 +9,8 @@ import os import sys -if sys.version_info < (2, 5): - print >>sys.stderr, "You must use at least Python 2.5 for Twisted" +if sys.version_info < (2, 6): + print >>sys.stderr, "You must use at least Python 2.6 for Twisted" sys.exit(3) if os.path.exists('twisted'): @@ -28,7 +28,8 @@ Extension("twisted.python._epoll", ["twisted/python/_epoll.c"], - condition=lambda builder: _isCPython and _hasEpoll(builder)), + condition=lambda builder: (_isCPython and _hasEpoll(builder) and + sys.version_info[:2] < (2, 6))), Extension("twisted.internet.iocpreactor.iocpsupport", ["twisted/internet/iocpreactor/iocpsupport/iocpsupport.c", @@ -38,6 +39,9 @@ Extension("twisted.python._initgroups", ["twisted/python/_initgroups.c"]), + Extension("twisted.python.sendmsg", + sources=["twisted/python/sendmsg.c"], + condition=lambda _: sys.platform != "win32"), Extension("twisted.internet._sigchld", ["twisted/internet/_sigchld.c"], condition=lambda _: sys.platform != "win32"), diff -Nru twisted-12.0.0/twisted/__init__.py twisted-12.2.0/twisted/__init__.py --- twisted-12.0.0/twisted/__init__.py 2011-11-20 15:19:42.000000000 +0000 +++ twisted-12.2.0/twisted/__init__.py 2012-08-03 09:39:21.000000000 +0000 @@ -10,8 +10,8 @@ # Ensure the user is running the version of python we require. import sys -if not hasattr(sys, "version_info") or sys.version_info < (2, 5): - raise RuntimeError("Twisted requires Python 2.5 or later.") +if not hasattr(sys, "version_info") or sys.version_info < (2, 6): + raise RuntimeError("Twisted requires Python 2.6 or later.") del sys # Ensure compat gets imported diff -Nru twisted-12.0.0/twisted/_version.py twisted-12.2.0/twisted/_version.py --- twisted-12.0.0/twisted/_version.py 2012-02-10 14:56:39.000000000 +0000 +++ twisted-12.2.0/twisted/_version.py 2012-08-26 12:13:01.000000000 +0000 @@ -1,3 +1,3 @@ # This is an auto-generated file. Do not edit it. from twisted.python import versions -version = versions.Version('twisted', 12, 0, 0) +version = versions.Version('twisted', 12, 2, 0) diff -Nru twisted-12.0.0/twisted/application/app.py twisted-12.2.0/twisted/application/app.py --- twisted-12.0.0/twisted/application/app.py 2011-10-18 10:31:11.000000000 +0000 +++ twisted-12.2.0/twisted/application/app.py 2012-03-12 07:01:11.000000000 +0000 @@ -653,12 +653,6 @@ -def initialLog(): - AppLogger({})._initialLog() -initialLog = deprecated(Version("Twisted", 8, 2, 0))(initialLog) - - - def convertStyle(filein, typein, passphrase, fileout, typeout, encrypt): application = service.loadApplication(filein, typein, passphrase) sob.IPersistable(application).setStyle(typeout) diff -Nru twisted-12.0.0/twisted/application/service.py twisted-12.2.0/twisted/application/service.py --- twisted-12.0.0/twisted/application/service.py 2011-09-30 19:22:51.000000000 +0000 +++ twisted-12.2.0/twisted/application/service.py 2012-06-07 13:15:27.000000000 +0000 @@ -169,7 +169,7 @@ def __getstate__(self): dict = self.__dict__.copy() - if dict.has_key("running"): + if "running" in dict: del dict['running'] return dict @@ -298,7 +298,7 @@ def addService(self, service): if service.name is not None: - if self.namedServices.has_key(service.name): + if service.name in self.namedServices: raise RuntimeError("cannot have two services with same name" " '%s'" % service.name) self.namedServices[service.name] = service diff -Nru twisted-12.0.0/twisted/application/strports.py twisted-12.2.0/twisted/application/strports.py --- twisted-12.0.0/twisted/application/strports.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/application/strports.py 2012-04-07 15:52:13.000000000 +0000 @@ -51,8 +51,8 @@ @type default: C{str} or C{None} - @param default: Do not use this parameter. It is deprecated since Twisted - 10.2.0. + @param default: Do not use this parameter. It has been deprecated since + Twisted 10.2.0. @rtype: C{twisted.application.service.IService} diff -Nru twisted-12.0.0/twisted/enterprise/adbapi.py twisted-12.2.0/twisted/enterprise/adbapi.py --- twisted-12.0.0/twisted/enterprise/adbapi.py 2012-01-06 13:16:05.000000000 +0000 +++ twisted-12.2.0/twisted/enterprise/adbapi.py 2012-06-07 13:15:27.000000000 +0000 @@ -218,7 +218,7 @@ for arg in self.CP_ARGS: cp_arg = 'cp_%s' % arg - if connkw.has_key(cp_arg): + if cp_arg in connkw: setattr(self, arg, connkw[cp_arg]) del connkw[cp_arg] diff -Nru twisted-12.0.0/twisted/internet/_glibbase.py twisted-12.2.0/twisted/internet/_glibbase.py --- twisted-12.0.0/twisted/internet/_glibbase.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/internet/_glibbase.py 2012-05-12 13:55:41.000000000 +0000 @@ -0,0 +1,387 @@ +# -*- test-case-name: twisted.internet.test -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +This module provides base support for Twisted to interact with the glib/gtk +mainloops. + +The classes in this module should not be used directly, but rather you should +import gireactor or gtk3reactor for GObject Introspection based applications, +or glib2reactor or gtk2reactor for applications using legacy static bindings. +""" + +import sys + +from twisted.internet import base, posixbase, selectreactor +from twisted.internet.interfaces import IReactorFDSet +from twisted.python import log +from twisted.python.compat import set +from zope.interface import implements + + +def ensureNotImported(moduleNames, errorMessage, preventImports=[]): + """ + Check whether the given modules were imported, and if requested, ensure + they will not be importable in the future. + + @param moduleNames: A list of module names we make sure aren't imported. + @type moduleNames: C{list} of C{str} + + @param preventImports: A list of module name whose future imports should + be prevented. + @type preventImports: C{list} of C{str} + + @param errorMessage: Message to use when raising an C{ImportError}. + @type errorMessage: C{str} + + @raises: C{ImportError} with given error message if a given module name + has already been imported. + """ + for name in moduleNames: + if sys.modules.get(name) is not None: + raise ImportError(errorMessage) + + # Disable module imports to avoid potential problems. + for name in preventImports: + sys.modules[name] = None + + + +class GlibWaker(posixbase._UnixWaker): + """ + Run scheduled events after waking up. + """ + + def doRead(self): + posixbase._UnixWaker.doRead(self) + self.reactor._simulate() + + + +class GlibReactorBase(posixbase.PosixReactorBase, posixbase._PollLikeMixin): + """ + Base class for GObject event loop reactors. + + Notification for I/O events (reads and writes on file descriptors) is done + by the the gobject-based event loop. File descriptors are registered with + gobject with the appropriate flags for read/write/disconnect notification. + + Time-based events, the results of C{callLater} and C{callFromThread}, are + handled differently. Rather than registering each event with gobject, a + single gobject timeout is registered for the earliest scheduled event, the + output of C{reactor.timeout()}. For example, if there are timeouts in 1, 2 + and 3.4 seconds, a single timeout is registered for 1 second in the + future. When this timeout is hit, C{_simulate} is called, which calls the + appropriate Twisted-level handlers, and a new timeout is added to gobject + by the C{_reschedule} method. + + To handle C{callFromThread} events, we use a custom waker that calls + C{_simulate} whenever it wakes up. + + @ivar _sources: A dictionary mapping L{FileDescriptor} instances to + GSource handles. + + @ivar _reads: A set of L{FileDescriptor} instances currently monitored for + reading. + + @ivar _writes: A set of L{FileDescriptor} instances currently monitored for + writing. + + @ivar _simtag: A GSource handle for the next L{simulate} call. + """ + implements(IReactorFDSet) + + # Install a waker that knows it needs to call C{_simulate} in order to run + # callbacks queued from a thread: + _wakerFactory = GlibWaker + + def __init__(self, glib_module, gtk_module, useGtk=False): + self._simtag = None + self._reads = set() + self._writes = set() + self._sources = {} + self._glib = glib_module + self._gtk = gtk_module + posixbase.PosixReactorBase.__init__(self) + + self._source_remove = self._glib.source_remove + self._timeout_add = self._glib.timeout_add + + def _mainquit(): + if self._gtk.main_level(): + self._gtk.main_quit() + + if useGtk: + self._pending = self._gtk.events_pending + self._iteration = self._gtk.main_iteration_do + self._crash = _mainquit + self._run = self._gtk.main + else: + self.context = self._glib.main_context_default() + self._pending = self.context.pending + self._iteration = self.context.iteration + self.loop = self._glib.MainLoop() + self._crash = lambda: self._glib.idle_add(self.loop.quit) + self._run = self.loop.run + + + def _handleSignals(self): + # First, install SIGINT and friends: + base._SignalReactorMixin._handleSignals(self) + # Next, since certain versions of gtk will clobber our signal handler, + # set all signal handlers again after the event loop has started to + # ensure they're *really* set. We don't call this twice so we don't + # leak file descriptors created in the SIGCHLD initialization: + self.callLater(0, posixbase.PosixReactorBase._handleSignals, self) + + + # The input_add function in pygtk1 checks for objects with a + # 'fileno' method and, if present, uses the result of that method + # as the input source. The pygtk2 input_add does not do this. The + # function below replicates the pygtk1 functionality. + + # In addition, pygtk maps gtk.input_add to _gobject.io_add_watch, and + # g_io_add_watch() takes different condition bitfields than + # gtk_input_add(). We use g_io_add_watch() here in case pygtk fixes this + # bug. + def input_add(self, source, condition, callback): + if hasattr(source, 'fileno'): + # handle python objects + def wrapper(ignored, condition): + return callback(source, condition) + fileno = source.fileno() + else: + fileno = source + wrapper = callback + return self._glib.io_add_watch( + fileno, condition, wrapper, + priority=self._glib.PRIORITY_DEFAULT_IDLE) + + + def _ioEventCallback(self, source, condition): + """ + Called by event loop when an I/O event occurs. + """ + log.callWithLogger( + source, self._doReadOrWrite, source, source, condition) + return True # True = don't auto-remove the source + + + def _add(self, source, primary, other, primaryFlag, otherFlag): + """ + Add the given L{FileDescriptor} for monitoring either for reading or + writing. If the file is already monitored for the other operation, we + delete the previous registration and re-register it for both reading + and writing. + """ + if source in primary: + return + flags = primaryFlag + if source in other: + self._source_remove(self._sources[source]) + flags |= otherFlag + self._sources[source] = self.input_add( + source, flags, self._ioEventCallback) + primary.add(source) + + + def addReader(self, reader): + """ + Add a L{FileDescriptor} for monitoring of data available to read. + """ + self._add(reader, self._reads, self._writes, + self.INFLAGS, self.OUTFLAGS) + + + def addWriter(self, writer): + """ + Add a L{FileDescriptor} for monitoring ability to write data. + """ + self._add(writer, self._writes, self._reads, + self.OUTFLAGS, self.INFLAGS) + + + def getReaders(self): + """ + Retrieve the list of current L{FileDescriptor} monitored for reading. + """ + return list(self._reads) + + + def getWriters(self): + """ + Retrieve the list of current L{FileDescriptor} monitored for writing. + """ + return list(self._writes) + + + def removeAll(self): + """ + Remove monitoring for all registered L{FileDescriptor}s. + """ + return self._removeAll(self._reads, self._writes) + + + def _remove(self, source, primary, other, flags): + """ + Remove monitoring the given L{FileDescriptor} for either reading or + writing. If it's still monitored for the other operation, we + re-register the L{FileDescriptor} for only that operation. + """ + if source not in primary: + return + self._source_remove(self._sources[source]) + primary.remove(source) + if source in other: + self._sources[source] = self.input_add( + source, flags, self._ioEventCallback) + else: + self._sources.pop(source) + + + def removeReader(self, reader): + """ + Stop monitoring the given L{FileDescriptor} for reading. + """ + self._remove(reader, self._reads, self._writes, self.OUTFLAGS) + + + def removeWriter(self, writer): + """ + Stop monitoring the given L{FileDescriptor} for writing. + """ + self._remove(writer, self._writes, self._reads, self.INFLAGS) + + + def iterate(self, delay=0): + """ + One iteration of the event loop, for trial's use. + + This is not used for actual reactor runs. + """ + self.runUntilCurrent() + while self._pending(): + self._iteration(0) + + + def crash(self): + """ + Crash the reactor. + """ + posixbase.PosixReactorBase.crash(self) + self._crash() + + + def stop(self): + """ + Stop the reactor. + """ + posixbase.PosixReactorBase.stop(self) + # The base implementation only sets a flag, to ensure shutting down is + # not reentrant. Unfortunately, this flag is not meaningful to the + # gobject event loop. We therefore call wakeUp() to ensure the event + # loop will call back into Twisted once this iteration is done. This + # will result in self.runUntilCurrent() being called, where the stop + # flag will trigger the actual shutdown process, eventually calling + # crash() which will do the actual gobject event loop shutdown. + self.wakeUp() + + + def run(self, installSignalHandlers=True): + """ + Run the reactor. + """ + self.callWhenRunning(self._reschedule) + self.startRunning(installSignalHandlers=installSignalHandlers) + if self._started: + self._run() + + + def callLater(self, *args, **kwargs): + """ + Schedule a C{DelayedCall}. + """ + result = posixbase.PosixReactorBase.callLater(self, *args, **kwargs) + # Make sure we'll get woken up at correct time to handle this new + # scheduled call: + self._reschedule() + return result + + + def _reschedule(self): + """ + Schedule a glib timeout for C{_simulate}. + """ + if self._simtag is not None: + self._source_remove(self._simtag) + self._simtag = None + timeout = self.timeout() + if timeout is not None: + self._simtag = self._timeout_add( + int(timeout * 1000), self._simulate, + priority=self._glib.PRIORITY_DEFAULT_IDLE) + + + def _simulate(self): + """ + Run timers, and then reschedule glib timeout for next scheduled event. + """ + self.runUntilCurrent() + self._reschedule() + + + +class PortableGlibReactorBase(selectreactor.SelectReactor): + """ + Base class for GObject event loop reactors that works on Windows. + + Sockets aren't supported by GObject's input_add on Win32. + """ + def __init__(self, glib_module, gtk_module, useGtk=False): + self._simtag = None + self._glib = glib_module + self._gtk = gtk_module + selectreactor.SelectReactor.__init__(self) + + self._source_remove = self._glib.source_remove + self._timeout_add = self._glib.timeout_add + + def _mainquit(): + if self._gtk.main_level(): + self._gtk.main_quit() + + if useGtk: + self._crash = _mainquit + self._run = self._gtk.main + else: + self.loop = self._glib.MainLoop() + self._crash = lambda: self._glib.idle_add(self.loop.quit) + self._run = self.loop.run + + + def crash(self): + selectreactor.SelectReactor.crash(self) + self._crash() + + + def run(self, installSignalHandlers=True): + self.startRunning(installSignalHandlers=installSignalHandlers) + self._timeout_add(0, self.simulate) + if self._started: + self._run() + + + def simulate(self): + """ + Run simulation loops and reschedule callbacks. + """ + if self._simtag is not None: + self._source_remove(self._simtag) + self.iterate() + timeout = min(self.timeout(), 0.01) + if timeout is None: + timeout = 0.01 + self._simtag = self._timeout_add( + int(timeout * 1000), self.simulate, + priority=self._glib.PRIORITY_DEFAULT_IDLE) diff -Nru twisted-12.0.0/twisted/internet/_oldtls.py twisted-12.2.0/twisted/internet/_oldtls.py --- twisted-12.0.0/twisted/internet/_oldtls.py 2011-10-15 21:21:45.000000000 +0000 +++ twisted-12.2.0/twisted/internet/_oldtls.py 2012-05-12 10:07:03.000000000 +0000 @@ -10,13 +10,14 @@ OpenSSL's non-blocking socket-based APIs (which this module probably does about 99% correctly, but see #4455 for an example of a problem with it). -Eventually, use of this module should emit a warning. See #4974 and 5014. +Support for older versions of pyOpenSSL is now deprecated and will be removed +(see #5014). @see: L{twisted.internet._newtls} @since: 11.1 """ -import os +import os, warnings from twisted.python.runtime import platformType if platformType == 'win32': @@ -28,7 +29,7 @@ from errno import EWOULDBLOCK from errno import ENOBUFS -from OpenSSL import SSL +from OpenSSL import SSL, __version__ as _sslversion from zope.interface import implements @@ -38,6 +39,11 @@ from twisted.internet.main import CONNECTION_DONE, CONNECTION_LOST from twisted.internet._ssl import _TLSDelayed +warnings.warn( + "Support for pyOpenSSL %s is deprecated. " + "Upgrade to pyOpenSSL 0.10 or newer." % (_sslversion,), + category=DeprecationWarning, + stacklevel=100) class _TLSMixin: _socketShutdownMethod = 'sock_shutdown' diff -Nru twisted-12.0.0/twisted/internet/_pollingfile.py twisted-12.2.0/twisted/internet/_pollingfile.py --- twisted-12.0.0/twisted/internet/_pollingfile.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/internet/_pollingfile.py 2012-04-14 00:21:00.000000000 +0000 @@ -234,16 +234,39 @@ pass self.lostCallback() + def writeSequence(self, seq): + """ + Append a C{list} or C{tuple} of bytes to the output buffer. + + @param seq: C{list} or C{tuple} of C{str} instances to be appended to + the output buffer. + + @raise TypeError: If C{seq} contains C{unicode}. + """ + if unicode in map(type, seq): + raise TypeError("Unicode not allowed in output buffer.") self.outQueue.extend(seq) + def write(self, data): + """ + Append some bytes to the output buffer. + + @param data: C{str} to be appended to the output buffer. + @type data: C{str}. + + @raise TypeError: If C{data} is C{unicode} instead of C{str}. + """ + if isinstance(data, unicode): + raise TypeError("Unicode not allowed in output buffer.") if self.disconnecting: return self.outQueue.append(data) if sum(map(len, self.outQueue)) > FULL_BUFFER_SIZE: self.bufferFull() + def checkWork(self): numBytesWritten = 0 if not self.outQueue: @@ -258,8 +281,6 @@ while self.outQueue: data = self.outQueue.pop(0) errCode = 0 - if isinstance(data, unicode): - raise TypeError("unicode not allowed") try: errCode, nBytesWritten = win32file.WriteFile(self.writePipe, data, None) diff -Nru twisted-12.0.0/twisted/internet/_posixstdio.py twisted-12.2.0/twisted/internet/_posixstdio.py --- twisted-12.0.0/twisted/internet/_posixstdio.py 2010-05-14 16:34:24.000000000 +0000 +++ twisted-12.2.0/twisted/internet/_posixstdio.py 2012-05-04 18:49:18.000000000 +0000 @@ -11,7 +11,7 @@ Maintainer: James Y Knight """ -import warnings, errno, os +import warnings from zope.interface import implements from twisted.internet import process, error, interfaces @@ -23,31 +23,20 @@ class StandardIO(object): - implements(interfaces.ITransport, interfaces.IProducer, interfaces.IConsumer, interfaces.IHalfCloseableDescriptor) + implements(interfaces.ITransport, interfaces.IProducer, + interfaces.IConsumer, interfaces.IHalfCloseableDescriptor) + _reader = None _writer = None disconnected = False disconnecting = False - def __init__(self, proto, stdin=0, stdout=1): - from twisted.internet import reactor + def __init__(self, proto, stdin=0, stdout=1, reactor=None): + if reactor is None: + from twisted.internet import reactor self.protocol = proto self._writer = process.ProcessWriter(reactor, self, 'write', stdout) - try: - self._writer.startReading() - except IOError, e: - if e.errno == errno.EPERM: - # epoll will reject certain file descriptors by raising - # EPERM. Most commonly, this means stdout was redirected to - # a regular file. - raise RuntimeError( - "This reactor does not support this type of file " - "descriptor (fd %d, mode %d) (for example, epollreactor " - "does not support normal files. See #4429)." % ( - stdout, os.fstat(stdout).st_mode)) - raise - self._reader = process.ProcessReader(reactor, self, 'read', stdin) self._reader.startReading() self.protocol.makeConnection(self) diff -Nru twisted-12.0.0/twisted/internet/_sigchld.c twisted-12.2.0/twisted/internet/_sigchld.c --- twisted-12.0.0/twisted/internet/_sigchld.c 2010-02-23 04:30:27.000000000 +0000 +++ twisted-12.2.0/twisted/internet/_sigchld.c 2012-07-15 11:06:08.000000000 +0000 @@ -12,7 +12,7 @@ static void got_signal(int sig) { int saved_errno = errno; - int ignored_result; + ssize_t ignored_result; /* write() errors are unhandled. If the buffer is full, we don't * care. What about other errors? */ diff -Nru twisted-12.0.0/twisted/internet/_sslverify.py twisted-12.2.0/twisted/internet/_sslverify.py --- twisted-12.0.0/twisted/internet/_sslverify.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/internet/_sslverify.py 2012-07-19 21:11:15.000000000 +0000 @@ -102,8 +102,8 @@ l = [] lablen = 0 def uniqueValues(mapping): - return dict.fromkeys(mapping.itervalues()).keys() - for k in uniqueValues(_x509names): + return set(mapping.itervalues()) + for k in sorted(uniqueValues(_x509names)): label = util.nameToLabel(k) lablen = max(len(label), lablen) v = getattr(self, k, None) diff -Nru twisted-12.0.0/twisted/internet/_threadedselect.py twisted-12.2.0/twisted/internet/_threadedselect.py --- twisted-12.0.0/twisted/internet/_threadedselect.py 2011-08-03 11:20:35.000000000 +0000 +++ twisted-12.2.0/twisted/internet/_threadedselect.py 2012-05-31 17:58:56.000000000 +0000 @@ -1,16 +1,10 @@ # -*- test-case-name: twisted.test.test_internet -*- -# # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. -from __future__ import generators - """ Threaded select reactor -Maintainer: Bob Ippolito - - The threadedselectreactor is a specialized reactor for integrating with arbitrary foreign event loop, such as those you find in GUI toolkits. diff -Nru twisted-12.0.0/twisted/internet/abstract.py twisted-12.2.0/twisted/internet/abstract.py --- twisted-12.0.0/twisted/internet/abstract.py 2011-12-11 03:20:29.000000000 +0000 +++ twisted-12.2.0/twisted/internet/abstract.py 2012-04-26 13:46:20.000000000 +0000 @@ -155,7 +155,7 @@ SEND_LIMIT = 128*1024 - implements(interfaces.IProducer, interfaces.IReadWriteDescriptor, + implements(interfaces.IPushProducer, interfaces.IReadWriteDescriptor, interfaces.IConsumer, interfaces.ITransport, interfaces.IHalfCloseableDescriptor) def __init__(self, reactor=None): @@ -234,7 +234,7 @@ l = self.writeSomeData(self.dataBuffer) # There is no writeSomeData implementation in Twisted which returns - # 0, but the documentation for writeSomeData used to claim negative + # < 0, but the documentation for writeSomeData used to claim negative # integers meant connection lost. Keep supporting this here, # although it may be worth deprecating and removing at some point. if l < 0 or isinstance(l, Exception): @@ -290,6 +290,34 @@ # override in subclasses self.connectionLost(reason) + + def _isSendBufferFull(self): + """ + Determine whether the user-space send buffer for this transport is full + or not. + + When the buffer contains more than C{self.bufferSize} bytes, it is + considered full. This might be improved by considering the size of the + kernel send buffer and how much of it is free. + + @return: C{True} if it is full, C{False} otherwise. + """ + return len(self.dataBuffer) + self._tempDataLen > self.bufferSize + + + def _maybePauseProducer(self): + """ + Possibly pause a producer, if there is one and the send buffer is full. + """ + # If we are responsible for pausing our producer, + if self.producer is not None and self.streamingProducer: + # and our buffer is full, + if self._isSendBufferFull(): + # pause it. + self.producerPaused = 1 + self.producer.pauseProducing() + + def write(self, data): """Reliably write some data. @@ -305,17 +333,13 @@ if data: self._tempDataBuffer.append(data) self._tempDataLen += len(data) - # If we are responsible for pausing our producer, - if self.producer is not None and self.streamingProducer: - # and our buffer is full, - if len(self.dataBuffer) + self._tempDataLen > self.bufferSize: - # pause it. - self.producerPaused = 1 - self.producer.pauseProducing() + self._maybePauseProducer() self.startWriting() + def writeSequence(self, iovec): - """Reliably write a sequence of data. + """ + Reliably write a sequence of data. Currently, this is a convenience method roughly equivalent to:: @@ -337,15 +361,10 @@ self._tempDataBuffer.extend(iovec) for i in iovec: self._tempDataLen += len(i) - # If we are responsible for pausing our producer, - if self.producer is not None and self.streamingProducer: - # and our buffer is full, - if len(self.dataBuffer) + self._tempDataLen > self.bufferSize: - # pause it. - self.producerPaused = 1 - self.producer.pauseProducing() + self._maybePauseProducer() self.startWriting() + def loseConnection(self, _connDone=failure.Failure(main.CONNECTION_DONE)): """Close the connection at the next available opportunity. diff -Nru twisted-12.0.0/twisted/internet/address.py twisted-12.2.0/twisted/internet/address.py --- twisted-12.0.0/twisted/internet/address.py 2011-12-11 03:20:29.000000000 +0000 +++ twisted-12.2.0/twisted/internet/address.py 2012-04-24 21:19:37.000000000 +0000 @@ -15,12 +15,18 @@ class _IPAddress(object, util.FancyEqMixin): """ - Object representing an IPv4 socket endpoint. + An L{_IPAddress} represents the address of an IP socket endpoint, providing + common behavior for IPv4 and IPv6. @ivar type: A string describing the type of transport, either 'TCP' or 'UDP'. - @ivar host: A string containing the dotted-quad IP address. + + @ivar host: A string containing the presentation format of the IP address; + for example, "127.0.0.1" or "::1". + @type host: C{str} + @ivar port: An integer representing the port number. + @type port: C{int} """ implements(IAddress) @@ -46,19 +52,29 @@ class IPv4Address(_IPAddress): """ - Object representing an IPv4 socket endpoint. + An L{IPv4Address} represents the address of an IPv4 socket endpoint. + + @ivar host: A string containing a dotted-quad IPv4 address; for example, + "127.0.0.1". + @type host: C{str} """ + def __init__(self, type, host, port, _bwHack=None): _IPAddress.__init__(self, type, host, port) if _bwHack is not None: - warnings.warn("twisted.internet.address.IPv4Address._bwHack is deprecated since Twisted 11.0", - DeprecationWarning, stacklevel=2) + warnings.warn("twisted.internet.address.IPv4Address._bwHack " + "is deprecated since Twisted 11.0", + DeprecationWarning, stacklevel=2) class IPv6Address(_IPAddress): """ - Object representing an IPv6 socket endpoint. + An L{IPv6Address} represents the address of an IPv6 socket endpoint. + + @ivar host: A string containing a colon-separated, hexadecimal formatted + IPv6 address; for example, "::1". + @type host: C{str} """ @@ -85,11 +101,11 @@ if getattr(os.path, 'samefile', None) is not None: def __eq__(self, other): """ - overriding L{util.FancyEqMixin} to ensure the os level samefile check - is done if the name attributes do not match. + overriding L{util.FancyEqMixin} to ensure the os level samefile + check is done if the name attributes do not match. """ res = super(UNIXAddress, self).__eq__(other) - if res == False: + if not res and self.name and other.name: try: return os.path.samefile(self.name, other.name) except OSError: @@ -102,6 +118,8 @@ def __hash__(self): + if self.name is None: + return hash((self.__class__, None)) try: s1 = os.stat(self.name) return hash((s1.st_ino, s1.st_dev)) diff -Nru twisted-12.0.0/twisted/internet/default.py twisted-12.2.0/twisted/internet/default.py --- twisted-12.0.0/twisted/internet/default.py 2011-05-05 02:48:02.000000000 +0000 +++ twisted-12.2.0/twisted/internet/default.py 2012-05-08 00:03:40.000000000 +0000 @@ -24,8 +24,7 @@ @return: A zero-argument callable which will install the selected reactor. """ - # Linux: Once is fixed - # epoll should be the default. + # Linux: epoll(7) is the fault, since it scales well. # # OS X: poll(2) is not exposed by Python because it doesn't # support all file descriptors (in particular, lack of PTY support @@ -34,15 +33,22 @@ # ), and also has same # restriction as poll(2) as far PTY support goes. # - # Windows: IOCP should eventually be default, but still has a few - # remaining bugs, - # e.g. . + # Windows: IOCP should eventually be default, but still has some serious + # bugs, e.g. . # - # We therefore choose poll(2) on non-OS X POSIX platforms, and - # select(2) everywhere else. - if platform.getType() == 'posix' and not platform.isMacOSX(): - from twisted.internet.pollreactor import install - else: + # We therefore choose epoll(7) on Linux, poll(2) on other non-OS X POSIX + # platforms, and select(2) everywhere else. + try: + if platform.isLinux(): + try: + from twisted.internet.epollreactor import install + except ImportError: + from twisted.internet.pollreactor import install + elif platform.getType() == 'posix' and not platform.isMacOSX(): + from twisted.internet.pollreactor import install + else: + from twisted.internet.selectreactor import install + except ImportError: from twisted.internet.selectreactor import install return install diff -Nru twisted-12.0.0/twisted/internet/endpoints.py twisted-12.2.0/twisted/internet/endpoints.py --- twisted-12.0.0/twisted/internet/endpoints.py 2011-10-11 11:43:33.000000000 +0000 +++ twisted-12.2.0/twisted/internet/endpoints.py 2012-08-04 11:59:34.000000000 +0000 @@ -1,3 +1,4 @@ + # -*- test-case-name: twisted.internet.test.test_endpoints -*- # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -11,34 +12,35 @@ @since: 10.1 """ +import os, socket + from zope.interface import implements, directlyProvides import warnings -from twisted.internet import interfaces, defer, error +from twisted.internet import interfaces, defer, error, fdesc, threads from twisted.internet.protocol import ClientFactory, Protocol -from twisted.plugin import getPlugins +from twisted.plugin import IPlugin, getPlugins from twisted.internet.interfaces import IStreamServerEndpointStringParser from twisted.internet.interfaces import IStreamClientEndpointStringParser from twisted.python.filepath import FilePath - +from twisted.python.systemd import ListenFDs +from twisted.internet.abstract import isIPv6Address +from twisted.internet import stdio +from twisted.internet.stdio import PipeAddress __all__ = ["clientFromString", "serverFromString", - "TCP4ServerEndpoint", "TCP4ClientEndpoint", + "TCP4ServerEndpoint", "TCP6ServerEndpoint", + "TCP4ClientEndpoint", "TCP6ClientEndpoint", "UNIXServerEndpoint", "UNIXClientEndpoint", - "SSL4ServerEndpoint", "SSL4ClientEndpoint"] + "SSL4ServerEndpoint", "SSL4ClientEndpoint", + "AdoptedStreamServerEndpoint", "StandardIOEndpoint"] class _WrappingProtocol(Protocol): """ Wrap another protocol in order to notify my user when a connection has been made. - - @ivar _connectedDeferred: The L{Deferred} that will callback - with the C{wrappedProtocol} when it is connected. - - @ivar _wrappedProtocol: An L{IProtocol} provider that will be - connected. """ def __init__(self, connectedDeferred, wrappedProtocol): @@ -52,9 +54,10 @@ self._connectedDeferred = connectedDeferred self._wrappedProtocol = wrappedProtocol - if interfaces.IHalfCloseableProtocol.providedBy( - self._wrappedProtocol): - directlyProvides(self, interfaces.IHalfCloseableProtocol) + for iface in [interfaces.IHalfCloseableProtocol, + interfaces.IFileDescriptorReceiver]: + if iface.providedBy(self._wrappedProtocol): + directlyProvides(self, iface) def logPrefix(self): @@ -82,6 +85,13 @@ return self._wrappedProtocol.dataReceived(data) + def fileDescriptorReceived(self, descriptor): + """ + Proxy C{fileDescriptorReceived} calls to our C{self._wrappedProtocol} + """ + return self._wrappedProtocol.fileDescriptorReceived(descriptor) + + def connectionLost(self, reason): """ Proxy C{connectionLost} calls to our C{self._wrappedProtocol} @@ -110,25 +120,58 @@ """ Wrap a factory in order to wrap the protocols it builds. - @ivar _wrappedFactory: A provider of I{IProtocolFactory} whose - buildProtocol method will be called and whose resulting protocol - will be wrapped. + @ivar _wrappedFactory: A provider of I{IProtocolFactory} whose buildProtocol + method will be called and whose resulting protocol will be wrapped. - @ivar _onConnection: An L{Deferred} that fires when the protocol is + @ivar _onConnection: A L{Deferred} that fires when the protocol is connected + + @ivar _connector: A L{connector } + that is managing the current or previous connection attempt. """ protocol = _WrappingProtocol - def __init__(self, wrappedFactory, canceller): + def __init__(self, wrappedFactory): """ @param wrappedFactory: A provider of I{IProtocolFactory} whose buildProtocol method will be called and whose resulting protocol will be wrapped. - @param canceller: An object that will be called to cancel the - L{self._onConnection} L{Deferred} """ self._wrappedFactory = wrappedFactory - self._onConnection = defer.Deferred(canceller=canceller) + self._onConnection = defer.Deferred(canceller=self._canceller) + + + def startedConnecting(self, connector): + """ + A connection attempt was started. Remember the connector which started + said attempt, for use later. + """ + self._connector = connector + + + def _canceller(self, deferred): + """ + The outgoing connection attempt was cancelled. Fail that L{Deferred} + with an L{error.ConnectingCancelledError}. + + @param deferred: The L{Deferred } that was cancelled; + should be the same as C{self._onConnection}. + @type deferred: L{Deferred } + + @note: This relies on startedConnecting having been called, so it may + seem as though there's a race condition where C{_connector} may not + have been set. However, using public APIs, this condition is + impossible to catch, because a connection API + (C{connectTCP}/C{SSL}/C{UNIX}) is always invoked before a + L{_WrappingFactory}'s L{Deferred } is returned to + C{connect()}'s caller. + + @return: C{None} + """ + deferred.errback( + error.ConnectingCancelledError( + self._connector.getDestination())) + self._connector.stopConnecting() def doStart(self): @@ -165,37 +208,54 @@ Errback the C{self._onConnection} L{Deferred} when the client connection fails. """ - self._onConnection.errback(reason) + if not self._onConnection.called: + self._onConnection.errback(reason) -class TCP4ServerEndpoint(object): +class StandardIOEndpoint(object): """ - TCP server endpoint with an IPv4 configuration + A Standard Input/Output endpoint + """ + implements(interfaces.IStreamServerEndpoint) - @ivar _reactor: An L{IReactorTCP} provider. + def __init__(self, reactor): + """ + @param reactor: The reactor for the endpoint + """ + self._reactor = reactor - @type _port: int - @ivar _port: The port number on which to listen for incoming connections. - @type _backlog: int - @ivar _backlog: size of the listen queue + def listen(self, stdioProtocolFactory): + """ + Implement L{IStreamServerEndpoint.listen} to listen on stdin/stdout + """ + return defer.execute(stdio.StandardIO, + stdioProtocolFactory.buildProtocol(PipeAddress())) - @type _interface: str - @ivar _interface: the hostname to bind to, defaults to '' (all) + + +class _TCPServerEndpoint(object): + """ + A TCP server endpoint interface """ implements(interfaces.IStreamServerEndpoint) - def __init__(self, reactor, port, backlog=50, interface=''): + def __init__(self, reactor, port, backlog, interface): """ @param reactor: An L{IReactorTCP} provider. - @param port: The port number used listening - @param backlog: size of the listen queue - @param interface: the hostname to bind to, defaults to '' (all) + + @param port: The port number used for listening + @type port: int + + @param backlog: Size of the listen queue + @type backlog: int + + @param interface: The hostname to bind to + @type interface: str """ self._reactor = reactor self._port = port - self._listenArgs = dict(backlog=50, interface='') self._backlog = backlog self._interface = interface @@ -212,37 +272,71 @@ -class TCP4ClientEndpoint(object): +class TCP4ServerEndpoint(_TCPServerEndpoint): """ - TCP client endpoint with an IPv4 configuration. + Implements TCP server endpoint with an IPv4 configuration + """ + def __init__(self, reactor, port, backlog=50, interface=''): + """ + @param reactor: An L{IReactorTCP} provider. - @ivar _reactor: An L{IReactorTCP} provider. + @param port: The port number used for listening + @type port: int - @type _host: str - @ivar _host: The hostname to connect to as a C{str} + @param backlog: Size of the listen queue + @type backlog: int - @type _port: int - @ivar _port: The port to connect to as C{int} + @param interface: The hostname to bind to, defaults to '' (all) + @type interface: str + """ + _TCPServerEndpoint.__init__(self, reactor, port, backlog, interface) - @type _timeout: int - @ivar _timeout: number of seconds to wait before assuming the - connection has failed. - @type _bindAddress: tuple - @type _bindAddress: a (host, port) tuple of local address to bind - to, or None. + +class TCP6ServerEndpoint(_TCPServerEndpoint): + """ + Implements TCP server endpoint with an IPv6 configuration + """ + def __init__(self, reactor, port, backlog=50, interface='::'): + """ + @param reactor: An L{IReactorTCP} provider. + + @param port: The port number used for listening + @type port: int + + @param backlog: Size of the listen queue + @type backlog: int + + @param interface: The hostname to bind to, defaults to '' (all) + @type interface: str + """ + _TCPServerEndpoint.__init__(self, reactor, port, backlog, interface) + + + +class TCP4ClientEndpoint(object): + """ + TCP client endpoint with an IPv4 configuration. """ implements(interfaces.IStreamClientEndpoint) def __init__(self, reactor, host, port, timeout=30, bindAddress=None): """ @param reactor: An L{IReactorTCP} provider + @param host: A hostname, used when connecting + @type host: str + @param port: The port number, used when connecting - @param timeout: number of seconds to wait before assuming the + @type port: int + + @param timeout: The number of seconds to wait before assuming the connection has failed. - @param bindAddress: a (host, port tuple of local address to bind to, + @type timeout: int + + @param bindAddress: A (host, port) tuple of local address to bind to, or None. + @type bindAddress: tuple """ self._reactor = reactor self._host = host @@ -255,14 +349,9 @@ """ Implement L{IStreamClientEndpoint.connect} to connect via TCP. """ - def _canceller(deferred): - connector.stopConnecting() - deferred.errback( - error.ConnectingCancelledError(connector.getDestination())) - try: - wf = _WrappingFactory(protocolFactory, _canceller) - connector = self._reactor.connectTCP( + wf = _WrappingFactory(protocolFactory) + self._reactor.connectTCP( self._host, self._port, wf, timeout=self._timeout, bindAddress=self._bindAddress) return wf._onConnection @@ -271,27 +360,80 @@ -class SSL4ServerEndpoint(object): +class TCP6ClientEndpoint(object): """ - SSL secured TCP server endpoint with an IPv4 configuration. + TCP client endpoint with an IPv6 configuration. + + @ivar _getaddrinfo: A hook used for testing name resolution. + + @ivar _deferToThread: A hook used for testing deferToThread. + + @ivar _GAI_ADDRESS: Index of the address portion in result of + getaddrinfo to be used. + + @ivar _GAI_ADDRESS_HOST: Index of the actual host-address in the + 5-tuple L{_GAI_ADDRESS}. + """ + _getaddrinfo = socket.getaddrinfo + _deferToThread = threads.deferToThread + _GAI_ADDRESS = 4 + _GAI_ADDRESS_HOST = 0 + + def __init__(self, reactor, host, port, timeout=30, bindAddress=None): + """ + @param host: An IPv6 address literal or a hostname with an + IPv6 address + + @see: L{twisted.internet.interfaces.IReactorTCP.connectTCP} + """ + self._reactor = reactor + self._host = host + self._port = port + self._timeout = timeout + self._bindAddress = bindAddress + + + def connect(self, protocolFactory): + """ + Implement L{IStreamClientEndpoint.connect} to connect via TCP, + once the hostname resolution is done. + """ + if isIPv6Address(self._host): + d = self._resolvedHostConnect(self._host, protocolFactory) + else: + d = self._nameResolution(self._host) + d.addCallback(lambda result: result[0][self._GAI_ADDRESS] + [self._GAI_ADDRESS_HOST]) + d.addCallback(self._resolvedHostConnect, protocolFactory) + return d - @ivar _reactor: An L{IReactorSSL} provider. - @type _host: str - @ivar _host: The hostname to connect to as a C{str} + def _nameResolution(self, host): + """ + Resolve the hostname string into a tuple containig the host + IPv6 address. + """ + return self._deferToThread( + self._getaddrinfo, host, 0, socket.AF_INET6) + - @type _port: int - @ivar _port: The port to connect to as C{int} + def _resolvedHostConnect(self, resolvedHost, protocolFactory): + """ + Connect to the server using the resolved hostname. + """ + try: + wf = _WrappingFactory(protocolFactory) + self._reactor.connectTCP(resolvedHost, self._port, wf, + timeout=self._timeout, bindAddress=self._bindAddress) + return wf._onConnection + except: + return defer.fail() - @type _sslContextFactory: L{OpenSSLCertificateOptions} - @var _sslContextFactory: SSL Configuration information as an - L{OpenSSLCertificateOptions} - @type _backlog: int - @ivar _backlog: size of the listen queue - @type _interface: str - @ivar _interface: the hostname to bind to, defaults to '' (all) +class SSL4ServerEndpoint(object): + """ + SSL secured TCP server endpoint with an IPv4 configuration. """ implements(interfaces.IStreamServerEndpoint) @@ -299,13 +441,18 @@ backlog=50, interface=''): """ @param reactor: An L{IReactorSSL} provider. - @param port: The port number used listening + + @param port: The port number used for listening + @type port: int + @param sslContextFactory: An instance of L{twisted.internet._sslverify.OpenSSLCertificateOptions}. - @param timeout: number of seconds to wait before assuming the - connection has failed. - @param bindAddress: a (host, port tuple of local address to bind to, - or None. + + @param backlog: Size of the listen queue + @type backlog: int + + @param interface: The hostname to bind to, defaults to '' (all) + @type interface: str """ self._reactor = reactor self._port = port @@ -330,26 +477,6 @@ class SSL4ClientEndpoint(object): """ SSL secured TCP client endpoint with an IPv4 configuration - - @ivar _reactor: An L{IReactorSSL} provider. - - @type _host: str - @ivar _host: The hostname to connect to as a C{str} - - @type _port: int - @ivar _port: The port to connect to as C{int} - - @type _sslContextFactory: L{OpenSSLCertificateOptions} - @var _sslContextFactory: SSL Configuration information as an - L{OpenSSLCertificateOptions} - - @type _timeout: int - @ivar _timeout: number of seconds to wait before assuming the - connection has failed. - - @type _bindAddress: tuple - @ivar _bindAddress: a (host, port) tuple of local address to bind - to, or None. """ implements(interfaces.IStreamClientEndpoint) @@ -357,14 +484,23 @@ timeout=30, bindAddress=None): """ @param reactor: An L{IReactorSSL} provider. + @param host: A hostname, used when connecting + @type host: str + @param port: The port number, used when connecting - @param sslContextFactory: SSL Configuration information as An instance + @type port: int + + @param sslContextFactory: SSL Configuration information as an instance of L{OpenSSLCertificateOptions}. - @param timeout: number of seconds to wait before assuming the + + @param timeout: Number of seconds to wait before assuming the connection has failed. - @param bindAddress: a (host, port tuple of local address to bind to, + @type timeout: int + + @param bindAddress: A (host, port) tuple of local address to bind to, or None. + @type bindAddress: tuple """ self._reactor = reactor self._host = host @@ -379,14 +515,9 @@ Implement L{IStreamClientEndpoint.connect} to connect with SSL over TCP. """ - def _canceller(deferred): - connector.stopConnecting() - deferred.errback( - error.ConnectingCancelledError(connector.getDestination())) - try: - wf = _WrappingFactory(protocolFactory, _canceller) - connector = self._reactor.connectSSL( + wf = _WrappingFactory(protocolFactory) + self._reactor.connectSSL( self._host, self._port, wf, self._sslContextFactory, timeout=self._timeout, bindAddress=self._bindAddress) return wf._onConnection @@ -398,15 +529,6 @@ class UNIXServerEndpoint(object): """ UnixSocket server endpoint. - - @type path: str - @ivar path: a path to a unix socket on the filesystem. - - @type _listenArgs: dict - @ivar _listenArgs: A C{dict} of keyword args that will be passed - to L{IReactorUNIX.listenUNIX} - - @var _reactor: An L{IReactorTCP} provider. """ implements(interfaces.IStreamServerEndpoint) @@ -414,13 +536,11 @@ """ @param reactor: An L{IReactorUNIX} provider. @param address: The path to the Unix socket file, used when listening - @param listenArgs: An optional dict of keyword args that will be - passed to L{IReactorUNIX.listenUNIX} @param backlog: number of connections to allow in backlog. @param mode: mode to set on the unix socket. This parameter is deprecated. Permissions should be set on the directory which contains the UNIX socket. - @param wantPID: if True, create a pidfile for the socket. + @param wantPID: If True, create a pidfile for the socket. """ self._reactor = reactor self._address = address @@ -444,30 +564,23 @@ class UNIXClientEndpoint(object): """ UnixSocket client endpoint. - - @type _path: str - @ivar _path: a path to a unix socket on the filesystem. - - @type _timeout: int - @ivar _timeout: number of seconds to wait before assuming the connection - has failed. - - @type _checkPID: bool - @ivar _checkPID: if True, check for a pid file to verify that a server - is listening. - - @var _reactor: An L{IReactorUNIX} provider. """ implements(interfaces.IStreamClientEndpoint) def __init__(self, reactor, path, timeout=30, checkPID=0): """ @param reactor: An L{IReactorUNIX} provider. + @param path: The path to the Unix socket file, used when connecting - @param timeout: number of seconds to wait before assuming the + @type path: str + + @param timeout: Number of seconds to wait before assuming the connection has failed. - @param checkPID: if True, check for a pid file to verify that a server + @type timeout: int + + @param checkPID: If True, check for a pid file to verify that a server is listening. + @type checkPID: bool """ self._reactor = reactor self._path = path @@ -480,14 +593,9 @@ Implement L{IStreamClientEndpoint.connect} to connect via a UNIX Socket """ - def _canceller(deferred): - connector.stopConnecting() - deferred.errback( - error.ConnectingCancelledError(connector.getDestination())) - try: - wf = _WrappingFactory(protocolFactory, _canceller) - connector = self._reactor.connectUNIX( + wf = _WrappingFactory(protocolFactory) + self._reactor.connectUNIX( self._path, wf, timeout=self._timeout, checkPID=self._checkPID) @@ -497,6 +605,53 @@ +class AdoptedStreamServerEndpoint(object): + """ + An endpoint for listening on a file descriptor initialized outside of + Twisted. + + @ivar _used: A C{bool} indicating whether this endpoint has been used to + listen with a factory yet. C{True} if so. + """ + _close = os.close + _setNonBlocking = staticmethod(fdesc.setNonBlocking) + + def __init__(self, reactor, fileno, addressFamily): + """ + @param reactor: An L{IReactorSocket} provider. + + @param fileno: An integer file descriptor corresponding to a listening + I{SOCK_STREAM} socket. + + @param addressFamily: The address family of the socket given by + C{fileno}. + """ + self.reactor = reactor + self.fileno = fileno + self.addressFamily = addressFamily + self._used = False + + + def listen(self, factory): + """ + Implement L{IStreamServerEndpoint.listen} to start listening on, and + then close, C{self._fileno}. + """ + if self._used: + return defer.fail(error.AlreadyListened()) + self._used = True + + try: + self._setNonBlocking(self.fileno) + port = self.reactor.adoptStreamPort( + self.fileno, self.addressFamily, factory) + self._close(self.fileno) + except: + return defer.fail() + return defer.succeed(port) + + + def _parseTCP(factory, port, interface="", backlog=50): """ Internal parser function for L{_parseServer} to convert the string @@ -566,7 +721,6 @@ @param factory: the protocol factory being parsed, or C{None}. (This was a leftover argument from when this code was in C{strports}, and is now mostly None and unused.) - @type factory: L{IProtocolFactory} or C{NoneType} @param port: the integer port number to bind @@ -601,9 +755,128 @@ return ((int(port), factory, cf), {'interface': interface, 'backlog': int(backlog)}) + + +class _StandardIOParser(object): + """ + Stream server endpoint string parser for the Standard I/O type. + + @ivar prefix: See L{IStreamClientEndpointStringParser.prefix}. + """ + implements(IPlugin, IStreamServerEndpointStringParser) + + prefix = "stdio" + + def _parseServer(self, reactor): + """ + Internal parser function for L{_parseServer} to convert the string + arguments into structured arguments for the L{StandardIOEndpoint} + + @param reactor: Reactor for the endpoint + """ + return StandardIOEndpoint(reactor) + + + def parseStreamServer(self, reactor, *args, **kwargs): + # Redirects to another function (self._parseServer), tricks zope.interface + # into believing the interface is correctly implemented. + return self._parseServer(reactor) + + + +class _SystemdParser(object): + """ + Stream server endpoint string parser for the I{systemd} endpoint type. + + @ivar prefix: See L{IStreamClientEndpointStringParser.prefix}. + + @ivar _sddaemon: A L{ListenFDs} instance used to translate an index into an + actual file descriptor. + """ + implements(IPlugin, IStreamServerEndpointStringParser) + + _sddaemon = ListenFDs.fromEnvironment() + + prefix = "systemd" + + def _parseServer(self, reactor, domain, index): + """ + Internal parser function for L{_parseServer} to convert the string + arguments for a systemd server endpoint into structured arguments for + L{AdoptedStreamServerEndpoint}. + + @param reactor: An L{IReactorSocket} provider. + + @param domain: The domain (or address family) of the socket inherited + from systemd. This is a string like C{"INET"} or C{"UNIX"}, ie the + name of an address family from the L{socket} module, without the + C{"AF_"} prefix. + @type domain: C{str} + + @param index: An offset into the list of file descriptors inherited from + systemd. + @type index: C{str} + + @return: A two-tuple of parsed positional arguments and parsed keyword + arguments (a tuple and a dictionary). These can be used to + construct an L{AdoptedStreamServerEndpoint}. + """ + index = int(index) + fileno = self._sddaemon.inheritedDescriptors()[index] + addressFamily = getattr(socket, 'AF_' + domain) + return AdoptedStreamServerEndpoint(reactor, fileno, addressFamily) + + + def parseStreamServer(self, reactor, *args, **kwargs): + # Delegate to another function with a sane signature. This function has + # an insane signature to trick zope.interface into believing the + # interface is correctly implemented. + return self._parseServer(reactor, *args, **kwargs) + + + +class _TCP6ServerParser(object): + """ + Stream server endpoint string parser for the TCP6ServerEndpoint type. + + @ivar prefix: See L{IStreamClientEndpointStringParser.prefix}. + """ + implements(IPlugin, IStreamServerEndpointStringParser) + + prefix = "tcp6" # Used in _parseServer to identify the plugin with the endpoint type + + def _parseServer(self, reactor, port, backlog=50, interface='::'): + """ + Internal parser function for L{_parseServer} to convert the string + arguments into structured arguments for the L{TCP6ServerEndpoint} + + @param reactor: An L{IReactorTCP} provider. + + @param port: The port number used for listening + @type port: int + + @param backlog: Size of the listen queue + @type backlog: int + + @param interface: The hostname to bind to + @type interface: str + """ + port = int(port) + backlog = int(backlog) + return TCP6ServerEndpoint(reactor, port, backlog, interface) + + + def parseStreamServer(self, reactor, *args, **kwargs): + # Redirects to another function (self._parseServer), tricks zope.interface + # into believing the interface is correctly implemented. + return self._parseServer(reactor, *args, **kwargs) + + + _serverParsers = {"tcp": _parseTCP, "unix": _parseUNIX, - "ssl": _parseSSL} + "ssl": _parseSSL, + } _OP, _STRING = range(2) @@ -727,8 +1000,10 @@ endpointType = args[0] parser = _serverParsers.get(endpointType) if parser is None: + # If the required parser is not found in _server, check if + # a plugin exists for the endpointType for plugin in getPlugins(IStreamServerEndpointStringParser): - if plugin.prefix == endpointType: + if plugin.prefix == endpointType: return (plugin, args[1:], kw) raise ValueError("Unknown endpoint type: '%s'" % (endpointType,)) return (endpointType.upper(),) + parser(factory, *args[1:], **kw) @@ -849,16 +1124,32 @@ -def _parseClientTCP(**kwargs): +def _parseClientTCP(*args, **kwargs): """ Perform any argument value coercion necessary for TCP client parameters. + Valid positional arguments to this function are host and port. + Valid keyword arguments to this function are all L{IReactorTCP.connectTCP} arguments. @return: The coerced values as a C{dict}. """ - kwargs['port'] = int(kwargs['port']) + + if len(args) == 2: + kwargs['port'] = int(args[1]) + kwargs['host'] = args[0] + elif len(args) == 1: + if 'host' in kwargs: + kwargs['port'] = int(args[0]) + else: + kwargs['host'] = args[0] + + try: + kwargs['port'] = int(kwargs['port']) + except KeyError: + pass + try: kwargs['timeout'] = int(kwargs['timeout']) except KeyError: @@ -898,7 +1189,7 @@ -def _parseClientSSL(**kwargs): +def _parseClientSSL(*args, **kwargs): """ Perform any argument value coercion necessary for SSL client parameters. @@ -907,7 +1198,9 @@ of the certificate file) C{privateKey} (the path name of the private key associated with the certificate) are accepted and used to construct a context factory. - + + Valid positional arguments to this function are host and port. + @param caCertsDir: The one parameter which is not part of L{IReactorSSL.connectSSL}'s signature, this is a path name used to construct a list of certificate authority certificates. The directory @@ -919,7 +1212,7 @@ @return: The coerced values as a C{dict}. """ from twisted.internet import ssl - kwargs = _parseClientTCP(**kwargs) + kwargs = _parseClientTCP(*args, **kwargs) certKey = kwargs.pop('certKey', None) privateKey = kwargs.pop('privateKey', None) caCertsDir = kwargs.pop('caCertsDir', None) @@ -950,16 +1243,21 @@ -def _parseClientUNIX(**kwargs): +def _parseClientUNIX(*args, **kwargs): """ Perform any argument value coercion necessary for UNIX client parameters. Valid keyword arguments to this function are all L{IReactorUNIX.connectUNIX} - arguments except for C{checkPID}. Instead, C{lockfile} is accepted and has - the same meaning. + keyword arguments except for C{checkPID}. Instead, C{lockfile} is accepted + and has the same meaning. Also C{path} is used instead of C{address}. + + Valid positional arguments to this function are C{path}. @return: The coerced values as a C{dict}. """ + if len(args) == 1: + kwargs['path'] = args[0] + try: kwargs['checkPID'] = bool(int(kwargs.pop('lockfile'))) except KeyError: @@ -983,19 +1281,27 @@ Construct a client endpoint from a description string. Client description strings are much like server description strings, - although they take all of their arguments as keywords, since even the - simplest client endpoint (plain TCP) requires at least 2 arguments (host - and port) to construct. + although they take all of their arguments as keywords, aside from host and + port. You can create a TCP client endpoint with the 'host' and 'port' arguments, like so:: clientFromString(reactor, "tcp:host=www.example.com:port=80") + or, without specifying host and port keywords:: + + clientFromString(reactor, "tcp:www.example.com:80") + + Or you can specify only one or the other, as in the following 2 examples:: + + clientFromString(reactor, "tcp:host=www.example.com:80") + clientFromString(reactor, "tcp:www.example.com:port=80") + or an SSL client endpoint with those arguments, plus the arguments used by the server SSL, for a client certificate:: - clientFromString(reactor, "ssl:host=web.example.com:port=443:" + clientFromString(reactor, "ssl:web.example.com:443:" "privateKey=foo.pem:certKey=foo.pem") to specify your certificate trust roots, you can identify a directory with @@ -1003,6 +1309,17 @@ clientFromString(reactor, "ssl:host=web.example.com:port=443:" "caCertsDir=/etc/ssl/certs") + + You can create a UNIX client endpoint with the 'path' argument and optional + 'lockfile' and 'timeout' arguments:: + + clientFromString(reactor, "unix:path=/var/foo/bar:lockfile=1:timeout=9") + + or, with the path as a positional argument with or without optional + arguments as in the following 2 examples:: + + clientFromString(reactor, "unix:/var/foo/bar") + clientFromString(reactor, "unix:/var/foo/bar:lockfile=1:timeout=9") This function is also extensible; new endpoint types may be registered as L{IStreamClientEndpointStringParser} plugins. See that interface for more diff -Nru twisted-12.0.0/twisted/internet/epollreactor.py twisted-12.2.0/twisted/internet/epollreactor.py --- twisted-12.0.0/twisted/internet/epollreactor.py 2012-01-01 13:28:50.000000000 +0000 +++ twisted-12.2.0/twisted/internet/epollreactor.py 2012-05-04 18:49:18.000000000 +0000 @@ -17,41 +17,190 @@ from twisted.internet.interfaces import IReactorFDSet -from twisted.python import log, _epoll +from twisted.python import log from twisted.internet import posixbase +try: + # In Python 2.6+, select.epoll provides epoll functionality. Try to import + # it, and fall back to Twisted's own epoll wrapper if it isn't available + # for any reason. + from select import epoll +except ImportError: + from twisted.python import _epoll +else: + del epoll + import select as _epoll + + + +class _ContinuousPolling(posixbase._PollLikeMixin, + posixbase._DisconnectSelectableMixin): + """ + Schedule reads and writes based on the passage of time, rather than + notification. + + This is useful for supporting polling filesystem files, which C{epoll(7)} + does not support. + + The implementation uses L{posixbase._PollLikeMixin}, which is a bit hacky, + but re-implementing and testing the relevant code yet again is + unappealing. + + @ivar _reactor: The L{EPollReactor} that is using this instance. + + @ivar _loop: A C{LoopingCall} that drives the polling, or C{None}. + + @ivar _readers: A C{set} of C{FileDescriptor} objects that should be read + from. + + @ivar _writers: A C{set} of C{FileDescriptor} objects that should be + written to. + """ + implements(IReactorFDSet) + + # Attributes for _PollLikeMixin + _POLL_DISCONNECTED = 1 + _POLL_IN = 2 + _POLL_OUT = 4 + + + def __init__(self, reactor): + self._reactor = reactor + self._loop = None + self._readers = set() + self._writers = set() + self.isReading = self._readers.__contains__ + self.isWriting = self._writers.__contains__ + + + def _checkLoop(self): + """ + Start or stop a C{LoopingCall} based on whether there are readers and + writers. + """ + if self._readers or self._writers: + if self._loop is None: + from twisted.internet.task import LoopingCall, _EPSILON + self._loop = LoopingCall(self.iterate) + self._loop.clock = self._reactor + # LoopingCall seems unhappy with timeout of 0, so use very + # small number: + self._loop.start(_EPSILON, now=False) + elif self._loop: + self._loop.stop() + self._loop = None + + + def iterate(self): + """ + Call C{doRead} and C{doWrite} on all readers and writers respectively. + """ + for reader in list(self._readers): + self._doReadOrWrite(reader, reader, self._POLL_IN) + for reader in list(self._writers): + self._doReadOrWrite(reader, reader, self._POLL_OUT) + + + def addReader(self, reader): + """ + Add a C{FileDescriptor} for notification of data available to read. + """ + self._readers.add(reader) + self._checkLoop() + + + def addWriter(self, writer): + """ + Add a C{FileDescriptor} for notification of data available to write. + """ + self._writers.add(writer) + self._checkLoop() + + + def removeReader(self, reader): + """ + Remove a C{FileDescriptor} from notification of data available to read. + """ + try: + self._readers.remove(reader) + except KeyError: + return + self._checkLoop() + + + def removeWriter(self, writer): + """ + Remove a C{FileDescriptor} from notification of data available to write. + """ + try: + self._writers.remove(writer) + except KeyError: + return + self._checkLoop() + + + def removeAll(self): + """ + Remove all readers and writers. + """ + result = list(self._readers | self._writers) + # Don't reset to new value, since self.isWriting and .isReading refer + # to the existing instance: + self._readers.clear() + self._writers.clear() + return result + + + def getReaders(self): + """ + Return a list of the readers. + """ + return list(self._readers) + + + def getWriters(self): + """ + Return a list of the writers. + """ + return list(self._writers) + + class EPollReactor(posixbase.PosixReactorBase, posixbase._PollLikeMixin): """ - A reactor that uses epoll(4). + A reactor that uses epoll(7). - @ivar _poller: A L{poll} which will be used to check for I/O + @ivar _poller: A C{epoll} which will be used to check for I/O readiness. @ivar _selectables: A dictionary mapping integer file descriptors to - instances of L{FileDescriptor} which have been registered with the - reactor. All L{FileDescriptors} which are currently receiving read or + instances of C{FileDescriptor} which have been registered with the + reactor. All C{FileDescriptors} which are currently receiving read or write readiness notifications will be present as values in this dictionary. @ivar _reads: A dictionary mapping integer file descriptors to arbitrary values (this is essentially a set). Keys in this dictionary will be registered with C{_poller} for read readiness notifications which will - be dispatched to the corresponding L{FileDescriptor} instances in + be dispatched to the corresponding C{FileDescriptor} instances in C{_selectables}. @ivar _writes: A dictionary mapping integer file descriptors to arbitrary values (this is essentially a set). Keys in this dictionary will be registered with C{_poller} for write readiness notifications which will - be dispatched to the corresponding L{FileDescriptor} instances in + be dispatched to the corresponding C{FileDescriptor} instances in C{_selectables}. + + @ivar _continuousPolling: A L{_ContinuousPolling} instance, used to handle + file descriptors (e.g. filesytem files) that are not supported by + C{epoll(7)}. """ implements(IReactorFDSet) # Attributes for _PollLikeMixin - _POLL_DISCONNECTED = (_epoll.HUP | _epoll.ERR) - _POLL_IN = _epoll.IN - _POLL_OUT = _epoll.OUT + _POLL_DISCONNECTED = (_epoll.EPOLLHUP | _epoll.EPOLLERR) + _POLL_IN = _epoll.EPOLLIN + _POLL_OUT = _epoll.EPOLLOUT def __init__(self): """ @@ -65,6 +214,7 @@ self._reads = {} self._writes = {} self._selectables = {} + self._continuousPolling = _ContinuousPolling(self) posixbase.PosixReactorBase.__init__(self) @@ -77,17 +227,17 @@ """ fd = xer.fileno() if fd not in primary: - cmd = _epoll.CTL_ADD flags = event - if fd in other: - flags |= antievent - cmd = _epoll.CTL_MOD # epoll_ctl can raise all kinds of IOErrors, and every one # indicates a bug either in the reactor or application-code. # Let them all through so someone sees a traceback and fixes # something. We'll do the same thing for every other call to # this method in this file. - self._poller._control(cmd, fd, flags) + if fd in other: + flags |= antievent + self._poller.modify(fd, flags) + else: + self._poller.register(fd, flags) # Update our own tracking state *only* after the epoll call has # succeeded. Otherwise we may get out of sync. @@ -99,14 +249,34 @@ """ Add a FileDescriptor for notification of data available to read. """ - self._add(reader, self._reads, self._writes, self._selectables, _epoll.IN, _epoll.OUT) + try: + self._add(reader, self._reads, self._writes, self._selectables, + _epoll.EPOLLIN, _epoll.EPOLLOUT) + except IOError, e: + if e.errno == errno.EPERM: + # epoll(7) doesn't support certain file descriptors, + # e.g. filesystem files, so for those we just poll + # continuously: + self._continuousPolling.addReader(reader) + else: + raise def addWriter(self, writer): """ Add a FileDescriptor for notification of data available to write. """ - self._add(writer, self._writes, self._reads, self._selectables, _epoll.OUT, _epoll.IN) + try: + self._add(writer, self._writes, self._reads, self._selectables, + _epoll.EPOLLOUT, _epoll.EPOLLIN) + except IOError, e: + if e.errno == errno.EPERM: + # epoll(7) doesn't support certain file descriptors, + # e.g. filesystem files, so for those we just poll + # continuously: + self._continuousPolling.addWriter(writer) + else: + raise def _remove(self, xer, primary, other, selectables, event, antievent): @@ -124,46 +294,57 @@ else: return if fd in primary: - cmd = _epoll.CTL_DEL - flags = event if fd in other: flags = antievent - cmd = _epoll.CTL_MOD + # See comment above modify call in _add. + self._poller.modify(fd, flags) else: del selectables[fd] + # See comment above _control call in _add. + self._poller.unregister(fd) del primary[fd] - # See comment above _control call in _add. - self._poller._control(cmd, fd, flags) def removeReader(self, reader): """ Remove a Selectable for notification of data available to read. """ - self._remove(reader, self._reads, self._writes, self._selectables, _epoll.IN, _epoll.OUT) + if self._continuousPolling.isReading(reader): + self._continuousPolling.removeReader(reader) + return + self._remove(reader, self._reads, self._writes, self._selectables, + _epoll.EPOLLIN, _epoll.EPOLLOUT) def removeWriter(self, writer): """ Remove a Selectable for notification of data available to write. """ - self._remove(writer, self._writes, self._reads, self._selectables, _epoll.OUT, _epoll.IN) + if self._continuousPolling.isWriting(writer): + self._continuousPolling.removeWriter(writer) + return + self._remove(writer, self._writes, self._reads, self._selectables, + _epoll.EPOLLOUT, _epoll.EPOLLIN) + def removeAll(self): """ Remove all selectables, and return a list of them. """ - return self._removeAll( - [self._selectables[fd] for fd in self._reads], - [self._selectables[fd] for fd in self._writes]) + return (self._removeAll( + [self._selectables[fd] for fd in self._reads], + [self._selectables[fd] for fd in self._writes]) + + self._continuousPolling.removeAll()) def getReaders(self): - return [self._selectables[fd] for fd in self._reads] + return ([self._selectables[fd] for fd in self._reads] + + self._continuousPolling.getReaders()) def getWriters(self): - return [self._selectables[fd] for fd in self._writes] + return ([self._selectables[fd] for fd in self._writes] + + self._continuousPolling.getWriters()) def doPoll(self, timeout): @@ -171,15 +352,14 @@ Poll the poller for new events. """ if timeout is None: - timeout = 1 - timeout = int(timeout * 1000) # convert seconds to milliseconds + timeout = -1 # Wait indefinitely. try: # Limit the number of events to the number of io objects we're # currently tracking (because that's maybe a good heuristic) and # the amount of time we block to the value specified by our # caller. - l = self._poller.wait(len(self._selectables), timeout) + l = self._poller.poll(timeout, len(self._selectables)) except IOError, err: if err.errno == errno.EINTR: return diff -Nru twisted-12.0.0/twisted/internet/error.py twisted-12.2.0/twisted/internet/error.py --- twisted-12.0.0/twisted/internet/error.py 2011-10-31 22:29:28.000000000 +0000 +++ twisted-12.2.0/twisted/internet/error.py 2012-04-26 13:46:20.000000000 +0000 @@ -243,6 +243,19 @@ +class FileDescriptorOverrun(ConnectionLost): + """ + A mis-use of L{IUNIXTransport.sendFileDescriptor} caused the connection to + be closed. + + Each file descriptor sent using C{sendFileDescriptor} must be associated + with at least one byte sent using L{ITransport.write}. If at any point + fewer bytes have been written than file descriptors have been sent, the + connection is closed with this exception. + """ + + + class ConnectionFdescWentAway(ConnectionLost): """Uh""" #TODO @@ -397,6 +410,28 @@ +class UnsupportedAddressFamily(Exception): + """ + An attempt was made to use a socket with an address family (eg I{AF_INET}, + I{AF_INET6}, etc) which is not supported by the reactor. + """ + + + +class UnsupportedSocketType(Exception): + """ + An attempt was made to use a socket of a type (eg I{SOCK_STREAM}, + I{SOCK_DGRAM}, etc) which is not supported by the reactor. + """ + + +class AlreadyListened(Exception): + """ + An attempt was made to listen on a file descriptor which can only be + listened on once. + """ + + __all__ = [ 'BindError', 'CannotListenError', 'MulticastJoinError', 'MessageLengthError', 'DNSLookupError', 'ConnectInProgressError', @@ -409,4 +444,5 @@ 'AlreadyCancelled', 'PotentialZombieWarning', 'ProcessDone', 'ProcessTerminated', 'ProcessExitedAlready', 'NotConnectingError', 'NotListeningError', 'ReactorNotRunning', 'ReactorAlreadyRunning', - 'ReactorAlreadyInstalledError', 'ConnectingCancelledError'] + 'ReactorAlreadyInstalledError', 'ConnectingCancelledError', + 'UnsupportedAddressFamily', 'UnsupportedSocketType'] diff -Nru twisted-12.0.0/twisted/internet/gireactor.py twisted-12.2.0/twisted/internet/gireactor.py --- twisted-12.0.0/twisted/internet/gireactor.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/internet/gireactor.py 2012-05-12 22:44:21.000000000 +0000 @@ -0,0 +1,139 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +This module provides support for Twisted to interact with the glib +mainloop via GObject Introspection. + +In order to use this support, simply do the following:: + + from twisted.internet import gireactor + gireactor.install() + +If you wish to use a GApplication, register it with the reactor:: + + from twisted.internet import reactor + reactor.registerGApplication(app) + +Then use twisted.internet APIs as usual. +""" + +import sys +from twisted.internet.error import ReactorAlreadyRunning +from twisted.internet import _glibbase +from twisted.python import runtime + +# We can't immediately prevent imports, because that confuses some buggy code +# in gi: +_glibbase.ensureNotImported( + ['gobject' 'glib', 'gio', 'gtk'], + "Introspected and static glib/gtk bindings must not be mixed; can't " + "import gireactor since pygtk2 module is already imported.") + +from gi.repository import GLib +GLib.threads_init() + +_glibbase.ensureNotImported([], "", + preventImports=['gobject' 'glib', 'gio', 'gtk']) + + + +class GIReactor(_glibbase.GlibReactorBase): + """ + GObject-introspection event loop reactor. + + @ivar _gapplication: A C{Gio.Application} instance that was registered + with C{registerGApplication}. + """ + _POLL_DISCONNECTED = (GLib.IOCondition.HUP | GLib.IOCondition.ERR | + GLib.IOCondition.NVAL) + _POLL_IN = GLib.IOCondition.IN + _POLL_OUT = GLib.IOCondition.OUT + + # glib's iochannel sources won't tell us about any events that we haven't + # asked for, even if those events aren't sensible inputs to the poll() + # call. + INFLAGS = _POLL_IN | _POLL_DISCONNECTED + OUTFLAGS = _POLL_OUT | _POLL_DISCONNECTED + + # By default no Application is registered: + _gapplication = None + + + def __init__(self, useGtk=False): + _gtk = None + if useGtk is True: + from gi.repository import Gtk as _gtk + + _glibbase.GlibReactorBase.__init__(self, GLib, _gtk, useGtk=useGtk) + + + def registerGApplication(self, app): + """ + Register a C{Gio.Application} or C{Gtk.Application}, whose main loop + will be used instead of the default one. + + We will C{hold} the application so it doesn't exit on its own. In + versions of C{python-gi} 3.2 and later, we exit the event loop using + the C{app.quit} method which overrides any holds. Older versions are + not supported. + """ + if self._gapplication is not None: + raise RuntimeError( + "Can't register more than one application instance.") + if self._started: + raise ReactorAlreadyRunning( + "Can't register application after reactor was started.") + if not hasattr(app, "quit"): + raise RuntimeError("Application registration is not supported in" + " versions of PyGObject prior to 3.2.") + self._gapplication = app + def run(): + app.hold() + app.run(None) + self._run = run + + self._crash = app.quit + + + +class PortableGIReactor(_glibbase.PortableGlibReactorBase): + """ + Portable GObject Introspection event loop reactor. + """ + def __init__(self, useGtk=False): + _gtk = None + if useGtk is True: + from gi.repository import Gtk as _gtk + + _glibbase.PortableGlibReactorBase.__init__(self, GLib, _gtk, + useGtk=useGtk) + + + def registerGApplication(self, app): + """ + Register a C{Gio.Application} or C{Gtk.Application}, whose main loop + will be used instead of the default one. + """ + raise NotImplementedError("GApplication is not currently supported on Windows.") + + + +def install(useGtk=False): + """ + Configure the twisted mainloop to be run inside the glib mainloop. + + @param useGtk: should GTK+ rather than glib event loop be + used (this will be slightly slower but does support GUI). + """ + if runtime.platform.getType() == 'posix': + reactor = GIReactor(useGtk=useGtk) + else: + reactor = PortableGIReactor(useGtk=useGtk) + + from twisted.internet.main import installReactor + installReactor(reactor) + return reactor + + +__all__ = ['install'] diff -Nru twisted-12.0.0/twisted/internet/glib2reactor.py twisted-12.2.0/twisted/internet/glib2reactor.py --- twisted-12.0.0/twisted/internet/glib2reactor.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-12.2.0/twisted/internet/glib2reactor.py 2012-01-25 03:20:58.000000000 +0000 @@ -1,3 +1,5 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. """ This module provides support for Twisted to interact with the glib mainloop. @@ -7,23 +9,16 @@ In order to use this support, simply do the following:: - | from twisted.internet import glib2reactor - | glib2reactor.install() + from twisted.internet import glib2reactor + glib2reactor.install() Then use twisted.internet APIs as usual. The other methods here are not intended to be called directly. - -When installing the reactor, you can choose whether to use the glib -event loop or the GTK+ event loop which is based on it but adds GUI -integration. - -Maintainer: Itamar Shtull-Trauring """ from twisted.internet import gtk2reactor - class Glib2Reactor(gtk2reactor.Gtk2Reactor): """ The reactor using the glib mainloop. @@ -44,6 +39,6 @@ reactor = Glib2Reactor() from twisted.internet.main import installReactor installReactor(reactor) - -__all__ = ['install'] + +__all__ = ['install'] diff -Nru twisted-12.0.0/twisted/internet/gtk2reactor.py twisted-12.2.0/twisted/internet/gtk2reactor.py --- twisted-12.0.0/twisted/internet/gtk2reactor.py 2011-12-08 19:02:05.000000000 +0000 +++ twisted-12.2.0/twisted/internet/gtk2reactor.py 2012-03-13 14:46:45.000000000 +0000 @@ -9,21 +9,25 @@ In order to use this support, simply do the following:: - | from twisted.internet import gtk2reactor - | gtk2reactor.install() + from twisted.internet import gtk2reactor + gtk2reactor.install() Then use twisted.internet APIs as usual. The other methods here are not intended to be called directly. - -When installing the reactor, you can choose whether to use the glib -event loop or the GTK+ event loop which is based on it but adds GUI -integration. """ # System Imports -import sys, signal +import sys + +# Twisted Imports +from twisted.internet import _glibbase +from twisted.python import runtime -from zope.interface import implements +_glibbase.ensureNotImported( + ["gi"], + "Introspected and static glib/gtk bindings must not be mixed; can't " + "import gtk2reactor since gi module is already imported.", + preventImports=["gi"]) try: if not hasattr(sys, 'frozen'): @@ -32,6 +36,7 @@ pygtk.require('2.0') except (ImportError, AttributeError): pass # maybe we're using pygtk before this hack existed. + import gobject if hasattr(gobject, "threads_init"): # recent versions of python-gtk expose this. python-gtk=2.4.1 @@ -39,363 +44,44 @@ # glib-2.2.3) does not. gobject.threads_init() -# Twisted Imports -from twisted.python import log, runtime -from twisted.python.compat import set -from twisted.internet.interfaces import IReactorFDSet -from twisted.internet import base, posixbase, selectreactor - -POLL_DISCONNECTED = gobject.IO_HUP | gobject.IO_ERR | gobject.IO_NVAL - -# glib's iochannel sources won't tell us about any events that we haven't -# asked for, even if those events aren't sensible inputs to the poll() -# call. -INFLAGS = gobject.IO_IN | POLL_DISCONNECTED -OUTFLAGS = gobject.IO_OUT | POLL_DISCONNECTED - - - -def _our_mainquit(): - # XXX: gtk.main_quit() (which is used for crash()) raises an exception if - # gtk.main_level() == 0; however, all the tests freeze if we use this - # function to stop the reactor. what gives? (I believe this may have been - # a stupid mistake where I forgot to import gtk here... I will remove this - # comment if the tests pass) - import gtk - if gtk.main_level(): - gtk.main_quit() - -class _Gtk2SignalMixin(object): - if runtime.platformType == 'posix': - def _handleSignals(self): - # Let the base class do its thing, but pygtk is probably - # going to stomp on us so go beyond that and set up some - # signal handling which pygtk won't mess with. This would - # be better done by letting this reactor select a - # different implementation of installHandler for - # _SIGCHLDWaker to use. Then, at least, we could fall - # back to our extension module. See #4286. - from twisted.internet.process import reapAllProcesses as _reapAllProcesses - base._SignalReactorMixin._handleSignals(self) - signal.signal(signal.SIGCHLD, lambda *a: self.callFromThread(_reapAllProcesses)) - if getattr(signal, "siginterrupt", None) is not None: - signal.siginterrupt(signal.SIGCHLD, False) - # Like the base, reap processes now in case a process - # exited before the handlers above were installed. - _reapAllProcesses() - - - -class _Gtk2Waker(posixbase._UnixWaker): +class Gtk2Reactor(_glibbase.GlibReactorBase): """ - Run scheduled events after waking up. + PyGTK+ 2 event loop reactor. """ - - def doRead(self): - posixbase._UnixWaker.doRead(self) - self.reactor._simulate() - - - -class Gtk2Reactor(_Gtk2SignalMixin, posixbase.PosixReactorBase, posixbase._PollLikeMixin): - """ - GTK+-2 event loop reactor. - - Notification for I/O events (reads and writes on file descriptors) is done - by the the gobject-based event loop. File descriptors are registered with - gobject with the appropriate flags for read/write/disconnect notification. - - Time-based events, the results of C{callLater} and C{callFromThread}, are - handled differently. Rather than registering each event with gobject, a - single gobject timeout is registered for the earliest scheduled event, the - output of C{reactor.timeout()}. For example, if there are timeouts in 1, 2 - and 3.4 seconds, a single timeout is registered for 1 second in the - future. When this timeout is hit, C{_simulate} is called, which calls the - appropriate Twisted-level handlers, and a new timeout is added to gobject - by the C{_reschedule} method. - - To handle C{callFromThread} events, we use a custom waker that calls - C{_simulate} whenever it wakes up. - - @ivar _sources: A dictionary mapping L{FileDescriptor} instances to gtk - watch handles. - - @ivar _reads: A set of L{FileDescriptor} instances currently monitored for - reading. - - @ivar _writes: A set of L{FileDescriptor} instances currently monitored for - writing. - - @ivar _simtag: A gtk timeout handle for the next L{_simulate} call. - """ - implements(IReactorFDSet) - - _POLL_DISCONNECTED = POLL_DISCONNECTED + _POLL_DISCONNECTED = gobject.IO_HUP | gobject.IO_ERR | gobject.IO_NVAL _POLL_IN = gobject.IO_IN _POLL_OUT = gobject.IO_OUT - # Install a waker that knows it needs to call C{_simulate} in order to run - # callbacks queued from a thread: - _wakerFactory = _Gtk2Waker + # glib's iochannel sources won't tell us about any events that we haven't + # asked for, even if those events aren't sensible inputs to the poll() + # call. + INFLAGS = _POLL_IN | _POLL_DISCONNECTED + OUTFLAGS = _POLL_OUT | _POLL_DISCONNECTED def __init__(self, useGtk=True): - self._simtag = None - self._reads = set() - self._writes = set() - self._sources = {} - posixbase.PosixReactorBase.__init__(self) - # pre 2.3.91 the glib iteration and mainloop functions didn't release - # global interpreter lock, thus breaking thread and signal support. - if getattr(gobject, "pygtk_version", ()) >= (2, 3, 91) and not useGtk: - self.context = gobject.main_context_default() - self.__pending = self.context.pending - self.__iteration = self.context.iteration - self.loop = gobject.MainLoop() - self.__crash = self.loop.quit - self.__run = self.loop.run - else: - import gtk - self.__pending = gtk.events_pending - self.__iteration = gtk.main_iteration - self.__crash = _our_mainquit - self.__run = gtk.main - - - # The input_add function in pygtk1 checks for objects with a - # 'fileno' method and, if present, uses the result of that method - # as the input source. The pygtk2 input_add does not do this. The - # function below replicates the pygtk1 functionality. - - # In addition, pygtk maps gtk.input_add to _gobject.io_add_watch, and - # g_io_add_watch() takes different condition bitfields than - # gtk_input_add(). We use g_io_add_watch() here in case pygtk fixes this - # bug. - def input_add(self, source, condition, callback): - if hasattr(source, 'fileno'): - # handle python objects - def wrapper(source, condition, real_s=source, real_cb=callback): - return real_cb(real_s, condition) - return gobject.io_add_watch(source.fileno(), condition, wrapper) - else: - return gobject.io_add_watch(source, condition, callback) - - - def _ioEventCallback(self, source, condition): - """ - Called by event loop when an I/O event occurs. - """ - log.callWithLogger( - source, self._doReadOrWrite, source, source, condition) - return 1 # 1=don't auto-remove the source - - - def _add(self, source, primary, other, primaryFlag, otherFlag): - """ - Add the given L{FileDescriptor} for monitoring either for reading or - writing. If the file is already monitored for the other operation, we - delete the previous registration and re-register it for both reading - and writing. - """ - if source in primary: - return - flags = primaryFlag - if source in other: - gobject.source_remove(self._sources[source]) - flags |= otherFlag - self._sources[source] = self.input_add( - source, flags, self._ioEventCallback) - primary.add(source) - - - def addReader(self, reader): - """ - Add a L{FileDescriptor} for monitoring of data available to read. - """ - self._add(reader, self._reads, self._writes, INFLAGS, OUTFLAGS) - - - def addWriter(self, writer): - """ - Add a L{FileDescriptor} for monitoring ability to write data. - """ - self._add(writer, self._writes, self._reads, OUTFLAGS, INFLAGS) - - - def getReaders(self): - """ - Retrieve the list of current L{FileDescriptor} monitored for reading. - """ - return list(self._reads) - - - def getWriters(self): - """ - Retrieve the list of current L{FileDescriptor} monitored for writing. - """ - return list(self._writes) - - - def removeAll(self): - """ - Remove monitoring for all registered L{FileDescriptor}s. - """ - return self._removeAll(self._reads, self._writes) - - - def _remove(self, source, primary, other, flags): - """ - Remove monitoring the given L{FileDescriptor} for either reading or - writing. If it's still monitored for the other operation, we - re-register the L{FileDescriptor} for only that operation. - """ - if source not in primary: - return - gobject.source_remove(self._sources[source]) - primary.remove(source) - if source in other: - self._sources[source] = self.input_add( - source, flags, self._ioEventCallback) - else: - self._sources.pop(source) - - - def removeReader(self, reader): - """ - Stop monitoring the given L{FileDescriptor} for reading. - """ - self._remove(reader, self._reads, self._writes, OUTFLAGS) - - - def removeWriter(self, writer): - """ - Stop monitoring the given L{FileDescriptor} for writing. - """ - self._remove(writer, self._writes, self._reads, INFLAGS) - - - def iterate(self, delay=0): - """ - One iteration of the event loop, for trial's use. - - This is not used for actual reactor runs. - """ - self.runUntilCurrent() - while self.__pending(): - self.__iteration(0) - - - def crash(self): - """ - Crash the reactor. - """ - posixbase.PosixReactorBase.crash(self) - self.__crash() - - - def stop(self): - """ - Stop the reactor. - """ - posixbase.PosixReactorBase.stop(self) - # The base implementation only sets a flag, to ensure shutting down is - # not reentrant. Unfortunately, this flag is not meaningful to the - # gobject event loop. We therefore call wakeUp() to ensure the event - # loop will call back into Twisted once this iteration is done. This - # will result in self.runUntilCurrent() being called, where the stop - # flag will trigger the actual shutdown process, eventually calling - # crash() which will do the actual gobject event loop shutdown. - self.wakeUp() - - - def run(self, installSignalHandlers=1): - """ - Run the reactor. - """ - self.callWhenRunning(self._reschedule) - self.startRunning(installSignalHandlers=installSignalHandlers) - if self._started: - self.__run() - - - def callLater(self, *args, **kwargs): - """ - Schedule a C{DelayedCall}. - """ - result = posixbase.PosixReactorBase.callLater(self, *args, **kwargs) - # Make sure we'll get woken up at correct time to handle this new - # scheduled call: - self._reschedule() - return result - - - def _reschedule(self): - """ - Schedule a glib timeout for C{_simulate}. - """ - if self._simtag is not None: - gobject.source_remove(self._simtag) - self._simtag = None - timeout = self.timeout() - if timeout is not None: - self._simtag = gobject.timeout_add(int(timeout * 1000), - self._simulate) - - - def _simulate(self): - """ - Run timers, and then reschedule glib timeout for next scheduled event. - """ - self.runUntilCurrent() - self._reschedule() + _gtk = None + if useGtk is True: + import gtk as _gtk + + _glibbase.GlibReactorBase.__init__(self, gobject, _gtk, useGtk=useGtk) -class PortableGtkReactor(_Gtk2SignalMixin, selectreactor.SelectReactor): +class PortableGtkReactor(_glibbase.PortableGlibReactorBase): """ Reactor that works on Windows. Sockets aren't supported by GTK+'s input_add on Win32. """ - _simtag = None - - def crash(self): - selectreactor.SelectReactor.crash(self) - import gtk - # mainquit is deprecated in newer versions - if gtk.main_level(): - if hasattr(gtk, 'main_quit'): - gtk.main_quit() - else: - gtk.mainquit() - - - def run(self, installSignalHandlers=1): - import gtk - self.startRunning(installSignalHandlers=installSignalHandlers) - gobject.timeout_add(0, self.simulate) - # mainloop is deprecated in newer versions - if self._started: - if hasattr(gtk, 'main'): - gtk.main() - else: - gtk.mainloop() - - - def simulate(self): - """ - Run simulation loops and reschedule callbacks. - """ - if self._simtag is not None: - gobject.source_remove(self._simtag) - self.iterate() - timeout = min(self.timeout(), 0.01) - if timeout is None: - timeout = 0.01 - # grumble - self._simtag = gobject.timeout_add(int(timeout * 1010), self.simulate) + def __init__(self, useGtk=True): + _gtk = None + if useGtk is True: + import gtk as _gtk + _glibbase.PortableGlibReactorBase.__init__(self, gobject, _gtk, + useGtk=useGtk) def install(useGtk=True): @@ -411,7 +97,6 @@ return reactor - def portableInstall(useGtk=True): """ Configure the twisted mainloop to be run inside the gtk mainloop. @@ -422,10 +107,8 @@ return reactor - if runtime.platform.getType() != 'posix': install = portableInstall - __all__ = ['install'] diff -Nru twisted-12.0.0/twisted/internet/gtk3reactor.py twisted-12.2.0/twisted/internet/gtk3reactor.py --- twisted-12.0.0/twisted/internet/gtk3reactor.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/internet/gtk3reactor.py 2012-05-12 22:44:21.000000000 +0000 @@ -0,0 +1,65 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +This module provides support for Twisted to interact with the gtk3 mainloop +via Gobject introspection. This is like gi, but slightly slower and requires a +working $DISPLAY. + +In order to use this support, simply do the following:: + + from twisted.internet import gtk3reactor + gtk3reactor.install() + +If you wish to use a GApplication, register it with the reactor:: + + from twisted.internet import reactor + reactor.registerGApplication(app) + +Then use twisted.internet APIs as usual. +""" + +from twisted.internet import gireactor +from twisted.python import runtime + + +class Gtk3Reactor(gireactor.GIReactor): + """ + A reactor using the gtk3+ event loop. + """ + + def __init__(self): + """ + Override init to set the C{useGtk} flag. + """ + gireactor.GIReactor.__init__(self, useGtk=True) + + + +class PortableGtk3Reactor(gireactor.PortableGIReactor): + """ + Portable GTK+ 3.x reactor. + """ + def __init__(self): + """ + Override init to set the C{useGtk} flag. + """ + gireactor.PortableGIReactor.__init__(self, useGtk=True) + + + +def install(): + """ + Configure the Twisted mainloop to be run inside the gtk3+ mainloop. + """ + if runtime.platform.getType() == 'posix': + reactor = Gtk3Reactor() + else: + reactor = PortableGtk3Reactor() + + from twisted.internet.main import installReactor + installReactor(reactor) + return reactor + + +__all__ = ['install'] diff -Nru twisted-12.0.0/twisted/internet/interfaces.py twisted-12.2.0/twisted/internet/interfaces.py --- twisted-12.0.0/twisted/internet/interfaces.py 2011-12-11 03:20:29.000000000 +0000 +++ twisted-12.2.0/twisted/internet/interfaces.py 2012-07-28 14:29:16.000000000 +0000 @@ -494,6 +494,105 @@ +class IReactorSocket(Interface): + """ + Methods which allow a reactor to use externally created sockets. + + For example, to use C{adoptStreamPort} to implement behavior equivalent + to that of L{IReactorTCP.listenTCP}, you might write code like this:: + + from socket import SOMAXCONN, AF_INET, SOCK_STREAM, socket + portSocket = socket(AF_INET, SOCK_STREAM) + # Set FD_CLOEXEC on port, left as an exercise. Then make it into a + # non-blocking listening port: + portSocket.setblocking(False) + portSocket.bind(('192.168.1.2', 12345)) + portSocket.listen(SOMAXCONN) + + # Now have the reactor use it as a TCP port + port = reactor.adoptStreamPort( + portSocket.fileno(), AF_INET, YourFactory()) + + # portSocket itself is no longer necessary, and needs to be cleaned + # up by us. + portSocket.close() + + # Whenever the server is no longer needed, stop it as usual. + stoppedDeferred = port.stopListening() + + Another potential use is to inherit a listening descriptor from a parent + process (for example, systemd or launchd), or to receive one over a UNIX + domain socket. + + Some plans for extending this interface exist. See: + + - U{http://twistedmatrix.com/trac/ticket/5570}: established connections + - U{http://twistedmatrix.com/trac/ticket/5573}: AF_UNIX ports + - U{http://twistedmatrix.com/trac/ticket/5574}: SOCK_DGRAM sockets + """ + + def adoptStreamPort(fileDescriptor, addressFamily, factory): + """ + Add an existing listening I{SOCK_STREAM} socket to the reactor to + monitor for new connections to accept and handle. + + @param fileDescriptor: A file descriptor associated with a socket which + is already bound to an address and marked as listening. The socket + must be set non-blocking. Any additional flags (for example, + close-on-exec) must also be set by application code. Application + code is responsible for closing the file descriptor, which may be + done as soon as C{adoptStreamPort} returns. + @type fileDescriptor: C{int} + + @param addressFamily: The address family (or I{domain}) of the socket. + For example, L{socket.AF_INET6}. + + @param factory: A L{ServerFactory} instance to use to create new + protocols to handle connections accepted via this socket. + + @return: An object providing L{IListeningPort}. + + @raise UnsupportedAddressFamily: If the given address family is not + supported by this reactor, or not supported with the given socket + type. + + @raise UnsupportedSocketType: If the given socket type is not supported + by this reactor, or not supported with the given socket type. + """ + + def adoptStreamConnection(fileDescriptor, addressFamily, factory): + """ + Add an existing connected I{SOCK_STREAM} socket to the reactor to + monitor for data. + + Note that the given factory won't have its C{startFactory} and + C{stopFactory} methods called, as there is no sensible time to call + them in this situation. + + @param fileDescriptor: A file descriptor associated with a socket which + is already connected. The socket must be set non-blocking. Any + additional flags (for example, close-on-exec) must also be set by + application code. Application code is responsible for closing the + file descriptor, which may be done as soon as + C{adoptStreamConnection} returns. + @type fileDescriptor: C{int} + + @param addressFamily: The address family (or I{domain}) of the socket. + For example, L{socket.AF_INET6}. + + @param factory: A L{ServerFactory} instance to use to create a new + protocol to handle the connection via this socket. + + @raise UnsupportedAddressFamily: If the given address family is not + supported by this reactor, or not supported with the given socket + type. + + @raise UnsupportedSocketType: If the given socket type is not supported + by this reactor, or not supported with the given socket type. + """ + + + class IReactorProcess(Interface): def spawnProcess(processProtocol, executable, args=(), env={}, path=None, @@ -872,6 +971,37 @@ """ +class IReactorDaemonize(Interface): + """ + A reactor which provides hooks that need to be called before and after + daemonization. + + Notes: + - This interface SHOULD NOT be called by applications. + - This interface should only be implemented by reactors as a workaround + (in particular, it's implemented currently only by kqueue()). + For details please see the comments on ticket #1918. + """ + + def beforeDaemonize(): + """ + Hook to be called immediately before daemonization. No reactor methods + may be called until L{afterDaemonize} is called. + + @return: C{None}. + """ + + + def afterDaemonize(): + """ + Hook to be called immediately after daemonization. This may only be + called after L{beforeDaemonize} had been called previously. + + @return: C{None}. + """ + + + class IReactorFDSet(Interface): """ Implement me to be able to use L{IFileDescriptor} type resources. @@ -1191,7 +1321,7 @@ class IPushProducer(IProducer): """ A push producer, also known as a streaming producer is expected to - produce (write to this consumer) data on a continous basis, unless + produce (write to this consumer) data on a continuous basis, unless it has been paused. A paused push producer will resume producing after its resumeProducing() method is called. For a push producer which is not pauseable, these functions may be noops. @@ -1357,7 +1487,7 @@ Notification of the read connection being closed. This indicates peer did half-close of write side. It is now - the responsiblity of the this protocol to call + the responsibility of the this protocol to call loseConnection(). In addition, the protocol MUST make sure a reference to it still exists (i.e. by doing a callLater with one of its methods, etc.) as the reactor will only have a @@ -1376,6 +1506,26 @@ """ + +class IFileDescriptorReceiver(Interface): + """ + Protocols may implement L{IFileDescriptorReceiver} to receive file + descriptors sent to them. This is useful in conjunction with + L{IUNIXTransport}, which allows file descriptors to be sent between + processes on a single host. + """ + def fileDescriptorReceived(descriptor): + """ + Called when a file descriptor is received over the connection. + + @param descriptor: The descriptor which was received. + @type descriptor: C{int} + + @return: C{None} + """ + + + class IProtocolFactory(Interface): """ Interface for protocol factories. @@ -1534,6 +1684,34 @@ """ + +class IUNIXTransport(ITransport): + """ + Transport for stream-oriented unix domain connections. + """ + def sendFileDescriptor(descriptor): + """ + Send a duplicate of this (file, socket, pipe, etc) descriptor to the + other end of this connection. + + The send is non-blocking and will be queued if it cannot be performed + immediately. The send will be processed in order with respect to other + C{sendFileDescriptor} calls on this transport, but not necessarily with + respect to C{write} calls on this transport. The send can only be + processed if there are also bytes in the normal connection-oriented send + buffer (ie, you must call C{write} at least as many times as you call + C{sendFileDescriptor}). + + @param descriptor: An C{int} giving a valid file descriptor in this + process. Note that a I{file descriptor} may actually refer to a + socket, a pipe, or anything else POSIX tries to treat in the same + way as a file. + + @return: C{None} + """ + + + class ITLSTransport(ITCPTransport): """ A TCP transport that supports switching to TLS midstream. @@ -1626,8 +1804,10 @@ - an integer, where it represents a POSIX signal ID. - @raise twisted.internet.error.ProcessExitedAlready: The process has - already exited. + @raise twisted.internet.error.ProcessExitedAlready: If the process has + already exited. + @raise OSError: If the C{os.kill} call fails with an errno different + from C{ESRCH}. """ @@ -1901,4 +2081,3 @@ @return: a client endpoint @rtype: L{IStreamClientEndpoint} """ - diff -Nru twisted-12.0.0/twisted/internet/iocpreactor/abstract.py twisted-12.2.0/twisted/internet/iocpreactor/abstract.py --- twisted-12.0.0/twisted/internet/iocpreactor/abstract.py 2011-11-14 00:41:17.000000000 +0000 +++ twisted-12.2.0/twisted/internet/iocpreactor/abstract.py 2012-03-15 20:18:28.000000000 +0000 @@ -22,7 +22,7 @@ """ File handle that can read and write asynchronously """ - implements(interfaces.IProducer, interfaces.IConsumer, + implements(interfaces.IPushProducer, interfaces.IConsumer, interfaces.ITransport, interfaces.IHalfCloseableDescriptor) # read stuff maxReadBuffers = 16 diff -Nru twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/acceptex.pxi twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/acceptex.pxi --- twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/acceptex.pxi 2011-11-25 21:21:10.000000000 +0000 +++ twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/acceptex.pxi 2012-03-12 23:15:18.000000000 +0000 @@ -24,6 +24,7 @@ if not rc: rc = WSAGetLastError() if rc != ERROR_IO_PENDING: + PyMem_Free(ov) return rc # operation is in progress diff -Nru twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/connectex.pxi twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/connectex.pxi --- twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/connectex.pxi 2011-03-17 03:34:22.000000000 +0000 +++ twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/connectex.pxi 2012-03-27 12:27:04.000000000 +0000 @@ -8,14 +8,23 @@ """ cdef int family, rc cdef myOVERLAPPED *ov - cdef sockaddr name + cdef sockaddr_in ipv4_name + cdef sockaddr_in6 ipv6_name + cdef sockaddr *name + cdef int namelen if not have_connectex: raise ValueError, 'ConnectEx is not available on this system' family = getAddrFamily(s) if family == AF_INET: - fillinetaddr(&name, addr) + name = &ipv4_name + namelen = sizeof(ipv4_name) + fillinetaddr(&ipv4_name, addr) + elif family == AF_INET6: + name = &ipv6_name + namelen = sizeof(ipv6_name) + fillinet6addr(&ipv6_name, addr) else: raise ValueError, 'unsupported address family' name.sa_family = family @@ -24,11 +33,12 @@ if obj is not None: ov.obj = obj - rc = lpConnectEx(s, &name, sizeof(name), NULL, 0, NULL, ov) + rc = lpConnectEx(s, name, namelen, NULL, 0, NULL, ov) if not rc: rc = WSAGetLastError() if rc != ERROR_IO_PENDING: + PyMem_Free(ov) return rc # operation is in progress diff -Nru twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c --- twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c 2011-11-25 21:21:10.000000000 +0000 +++ twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/iocpsupport.c 2012-03-27 12:27:04.000000000 +0000 @@ -1,4 +1,4 @@ -/* Generated by Cython 0.15.1 on Fri Nov 25 21:01:57 2011 */ +/* Generated by Cython 0.15.1 on Tue Mar 27 07:16:06 2012 */ #define PY_SSIZE_T_CLEAN #include "Python.h" @@ -378,7 +378,7 @@ struct __pyx_obj_11iocpsupport_CompletionPort; struct __pyx_t_11iocpsupport_myOVERLAPPED; -/* "iocpsupport.pyx":115 +/* "iocpsupport.pyx":124 * # BOOL (*lpTransmitFile)(SOCKET s, HANDLE hFile, DWORD size, DWORD buffer_size, OVERLAPPED *ov, TRANSMIT_FILE_BUFFERS *buff, DWORD flags) * * cdef struct myOVERLAPPED: # <<<<<<<<<<<<<< @@ -390,7 +390,7 @@ struct PyObject *obj; }; -/* "iocpsupport.pyx":139 +/* "iocpsupport.pyx":148 * setattr(self, k, v) * * cdef class CompletionPort: # <<<<<<<<<<<<<< @@ -619,6 +619,7 @@ static void __pyx_f_11iocpsupport_raise_error(int, PyObject *); /*proto*/ static PyObject *__pyx_f_11iocpsupport__makesockaddr(struct sockaddr *, Py_ssize_t); /*proto*/ static PyObject *__pyx_f_11iocpsupport_fillinetaddr(struct sockaddr_in *, PyObject *); /*proto*/ +static PyObject *__pyx_f_11iocpsupport_fillinet6addr(struct sockaddr_in6 *, PyObject *); /*proto*/ static int __pyx_f_11iocpsupport_getAddrFamily(__pyx_t_11iocpsupport_SOCKET); /*proto*/ #define __Pyx_MODULE_NAME "iocpsupport" int __pyx_module_is_main_iocpsupport = 0; @@ -626,17 +627,21 @@ /* Implementation of 'iocpsupport' */ static PyObject *__pyx_builtin_ValueError; static PyObject *__pyx_builtin_MemoryError; +static PyObject *__pyx_builtin_RuntimeError; static char __pyx_k_1[] = "CreateIoCompletionPort"; static char __pyx_k_2[] = "PostQueuedCompletionStatus"; static char __pyx_k_3[] = ":"; static char __pyx_k_5[] = "["; static char __pyx_k_6[] = "]"; static char __pyx_k_7[] = "invalid IP address"; -static char __pyx_k_8[] = "ConnectEx is not available on this system"; -static char __pyx_k_9[] = "unsupported address family"; -static char __pyx_k_10[] = "second argument needs to be a list"; -static char __pyx_k_11[] = "length of address length buffer needs to be sizeof(int)"; -static char __pyx_k_12[] = "Failed to initialize Winsock function vectors"; +static char __pyx_k_8[] = "%"; +static char __pyx_k_10[] = "invalid IPv6 address %r"; +static char __pyx_k_11[] = "undefined error occurred during address parsing"; +static char __pyx_k_12[] = "ConnectEx is not available on this system"; +static char __pyx_k_13[] = "unsupported address family"; +static char __pyx_k_14[] = "second argument needs to be a list"; +static char __pyx_k_15[] = "length of address length buffer needs to be sizeof(int)"; +static char __pyx_k_16[] = "Failed to initialize Winsock function vectors"; static char __pyx_k__s[] = "s"; static char __pyx_k__key[] = "key"; static char __pyx_k__obj[] = "obj"; @@ -649,6 +654,7 @@ static char __pyx_k__bytes[] = "bytes"; static char __pyx_k__flags[] = "flags"; static char __pyx_k__owner[] = "owner"; +static char __pyx_k__split[] = "split"; static char __pyx_k__accept[] = "accept"; static char __pyx_k__handle[] = "handle"; static char __pyx_k__rsplit[] = "rsplit"; @@ -668,6 +674,7 @@ static char __pyx_k__maxAddrLen[] = "maxAddrLen"; static char __pyx_k__MemoryError[] = "MemoryError"; static char __pyx_k__iocpsupport[] = "iocpsupport"; +static char __pyx_k__RuntimeError[] = "RuntimeError"; static char __pyx_k__WindowsError[] = "WindowsError"; static char __pyx_k__makesockaddr[] = "makesockaddr"; static char __pyx_k__addr_len_buff[] = "addr_len_buff"; @@ -676,18 +683,22 @@ static char __pyx_k__AllocateReadBuffer[] = "AllocateReadBuffer"; static char __pyx_k__WSAAddressToString[] = "WSAAddressToString"; static PyObject *__pyx_n_s_1; +static PyObject *__pyx_kp_s_10; static PyObject *__pyx_kp_s_11; static PyObject *__pyx_kp_s_12; +static PyObject *__pyx_kp_s_13; +static PyObject *__pyx_kp_s_15; +static PyObject *__pyx_kp_s_16; static PyObject *__pyx_n_s_2; static PyObject *__pyx_kp_s_3; static PyObject *__pyx_kp_s_5; static PyObject *__pyx_kp_s_6; static PyObject *__pyx_kp_s_7; static PyObject *__pyx_kp_s_8; -static PyObject *__pyx_kp_s_9; static PyObject *__pyx_n_s__AllocateReadBuffer; static PyObject *__pyx_n_s__Event; static PyObject *__pyx_n_s__MemoryError; +static PyObject *__pyx_n_s__RuntimeError; static PyObject *__pyx_n_s__ValueError; static PyObject *__pyx_n_s__WSAAddressToString; static PyObject *__pyx_n_s__WindowsError; @@ -723,11 +734,13 @@ static PyObject *__pyx_n_s__self; static PyObject *__pyx_n_s__send; static PyObject *__pyx_n_s__socket; +static PyObject *__pyx_n_s__split; static PyObject *__pyx_int_0; static PyObject *__pyx_int_1; static PyObject *__pyx_k_tuple_4; +static PyObject *__pyx_k_tuple_9; -/* "iocpsupport.pyx":119 +/* "iocpsupport.pyx":128 * PyObject *obj * * cdef myOVERLAPPED *makeOV() except NULL: # <<<<<<<<<<<<<< @@ -746,17 +759,17 @@ int __pyx_clineno = 0; __Pyx_RefNannySetupContext("makeOV"); - /* "iocpsupport.pyx":121 + /* "iocpsupport.pyx":130 * cdef myOVERLAPPED *makeOV() except NULL: * cdef myOVERLAPPED *res * res = PyMem_Malloc(sizeof(myOVERLAPPED)) # <<<<<<<<<<<<<< * if not res: * raise MemoryError */ - __pyx_t_1 = PyMem_Malloc((sizeof(struct __pyx_t_11iocpsupport_myOVERLAPPED))); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 121; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyMem_Malloc((sizeof(struct __pyx_t_11iocpsupport_myOVERLAPPED))); if (unlikely(__pyx_t_1 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_res = ((struct __pyx_t_11iocpsupport_myOVERLAPPED *)__pyx_t_1); - /* "iocpsupport.pyx":122 + /* "iocpsupport.pyx":131 * cdef myOVERLAPPED *res * res = PyMem_Malloc(sizeof(myOVERLAPPED)) * if not res: # <<<<<<<<<<<<<< @@ -766,19 +779,19 @@ __pyx_t_2 = (!(__pyx_v_res != 0)); if (__pyx_t_2) { - /* "iocpsupport.pyx":123 + /* "iocpsupport.pyx":132 * res = PyMem_Malloc(sizeof(myOVERLAPPED)) * if not res: * raise MemoryError # <<<<<<<<<<<<<< * memset(res, 0, sizeof(myOVERLAPPED)) * return res */ - PyErr_NoMemory(); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + PyErr_NoMemory(); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L3; } __pyx_L3:; - /* "iocpsupport.pyx":124 + /* "iocpsupport.pyx":133 * if not res: * raise MemoryError * memset(res, 0, sizeof(myOVERLAPPED)) # <<<<<<<<<<<<<< @@ -787,7 +800,7 @@ */ memset(__pyx_v_res, 0, (sizeof(struct __pyx_t_11iocpsupport_myOVERLAPPED))); - /* "iocpsupport.pyx":125 + /* "iocpsupport.pyx":134 * raise MemoryError * memset(res, 0, sizeof(myOVERLAPPED)) * return res # <<<<<<<<<<<<<< @@ -807,7 +820,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":127 +/* "iocpsupport.pyx":136 * return res * * cdef void raise_error(int err, object message) except *: # <<<<<<<<<<<<<< @@ -826,7 +839,7 @@ int __pyx_clineno = 0; __Pyx_RefNannySetupContext("raise_error"); - /* "iocpsupport.pyx":128 + /* "iocpsupport.pyx":137 * * cdef void raise_error(int err, object message) except *: * if not err: # <<<<<<<<<<<<<< @@ -836,7 +849,7 @@ __pyx_t_1 = (!__pyx_v_err); if (__pyx_t_1) { - /* "iocpsupport.pyx":129 + /* "iocpsupport.pyx":138 * cdef void raise_error(int err, object message) except *: * if not err: * err = GetLastError() # <<<<<<<<<<<<<< @@ -848,18 +861,18 @@ } __pyx_L3:; - /* "iocpsupport.pyx":130 + /* "iocpsupport.pyx":139 * if not err: * err = GetLastError() * raise WindowsError(message, err) # <<<<<<<<<<<<<< * * class Event: */ - __pyx_t_2 = __Pyx_GetName(__pyx_b, __pyx_n_s__WindowsError); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __Pyx_GetName(__pyx_b, __pyx_n_s__WindowsError); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyInt_FromLong(__pyx_v_err); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyInt_FromLong(__pyx_v_err); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); __Pyx_INCREF(__pyx_v_message); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_message); @@ -867,13 +880,13 @@ PyTuple_SET_ITEM(__pyx_t_4, 1, __pyx_t_3); __Pyx_GIVEREF(__pyx_t_3); __pyx_t_3 = 0; - __pyx_t_3 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyObject_Call(__pyx_t_2, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; __Pyx_Raise(__pyx_t_3, 0, 0, 0); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 130; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L0; __pyx_L1_error:; @@ -885,7 +898,7 @@ __Pyx_RefNannyFinishContext(); } -/* "iocpsupport.pyx":133 +/* "iocpsupport.pyx":142 * * class Event: * def __init__(self, callback, owner, **kw): # <<<<<<<<<<<<<< @@ -942,17 +955,17 @@ values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__callback); if (likely(values[1])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } case 2: values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__owner); if (likely(values[2])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_kw, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, __pyx_v_kw, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { goto __pyx_L5_argtuple_error; @@ -967,7 +980,7 @@ } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("__init__", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_DECREF(__pyx_v_kw); __pyx_v_kw = 0; __Pyx_AddTraceback("iocpsupport.Event.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); @@ -975,25 +988,25 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":134 + /* "iocpsupport.pyx":143 * class Event: * def __init__(self, callback, owner, **kw): * self.callback = callback # <<<<<<<<<<<<<< * self.owner = owner * for k, v in kw.items(): */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__callback, __pyx_v_callback) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__callback, __pyx_v_callback) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /* "iocpsupport.pyx":135 + /* "iocpsupport.pyx":144 * def __init__(self, callback, owner, **kw): * self.callback = callback * self.owner = owner # <<<<<<<<<<<<<< * for k, v in kw.items(): * setattr(self, k, v) */ - if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__owner, __pyx_v_owner) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 135; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_v_self, __pyx_n_s__owner, __pyx_v_owner) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 144; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /* "iocpsupport.pyx":136 + /* "iocpsupport.pyx":145 * self.callback = callback * self.owner = owner * for k, v in kw.items(): # <<<<<<<<<<<<<< @@ -1001,15 +1014,15 @@ * */ if (unlikely(((PyObject *)__pyx_v_kw) == Py_None)) { - PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", "items"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", "items"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } - __pyx_t_1 = PyDict_Items(__pyx_v_kw); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyDict_Items(__pyx_v_kw); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); if (PyList_CheckExact(__pyx_t_1) || PyTuple_CheckExact(__pyx_t_1)) { __pyx_t_2 = __pyx_t_1; __Pyx_INCREF(__pyx_t_2); __pyx_t_3 = 0; __pyx_t_4 = NULL; } else { - __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = -1; __pyx_t_2 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_t_4 = Py_TYPE(__pyx_t_2)->tp_iternext; } @@ -1026,7 +1039,7 @@ if (unlikely(!__pyx_t_1)) { if (PyErr_Occurred()) { if (likely(PyErr_ExceptionMatches(PyExc_StopIteration))) PyErr_Clear(); - else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + else {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } break; } @@ -1038,7 +1051,7 @@ if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) { if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2); else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence)); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } __pyx_t_5 = PyTuple_GET_ITEM(sequence, 0); __pyx_t_6 = PyTuple_GET_ITEM(sequence, 1); @@ -1046,7 +1059,7 @@ if (unlikely(PyList_GET_SIZE(sequence) != 2)) { if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2); else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence)); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } __pyx_t_5 = PyList_GET_ITEM(sequence, 0); __pyx_t_6 = PyList_GET_ITEM(sequence, 1); @@ -1056,7 +1069,7 @@ __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; } else { Py_ssize_t index = -1; - __pyx_t_7 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_7 = PyObject_GetIter(__pyx_t_1); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_7); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_8 = Py_TYPE(__pyx_t_7)->tp_iternext; @@ -1064,14 +1077,14 @@ __Pyx_GOTREF(__pyx_t_5); index = 1; __pyx_t_6 = __pyx_t_8(__pyx_t_7); if (unlikely(!__pyx_t_6)) goto __pyx_L8_unpacking_failed; __Pyx_GOTREF(__pyx_t_6); - if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (__Pyx_IternextUnpackEndCheck(__pyx_t_8(__pyx_t_7), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; goto __pyx_L9_unpacking_done; __pyx_L8_unpacking_failed:; __Pyx_DECREF(__pyx_t_7); __pyx_t_7 = 0; if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear(); if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 136; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_L9_unpacking_done:; } __Pyx_XDECREF(__pyx_v_k); @@ -1081,14 +1094,14 @@ __pyx_v_v = __pyx_t_6; __pyx_t_6 = 0; - /* "iocpsupport.pyx":137 + /* "iocpsupport.pyx":146 * self.owner = owner * for k, v in kw.items(): * setattr(self, k, v) # <<<<<<<<<<<<<< * * cdef class CompletionPort: */ - __pyx_t_9 = PyObject_SetAttr(__pyx_v_self, __pyx_v_k, __pyx_v_v); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 137; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_9 = PyObject_SetAttr(__pyx_v_self, __pyx_v_k, __pyx_v_v); if (unlikely(__pyx_t_9 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 146; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; @@ -1111,7 +1124,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":141 +/* "iocpsupport.pyx":150 * cdef class CompletionPort: * cdef HANDLE port * def __init__(self): # <<<<<<<<<<<<<< @@ -1134,7 +1147,7 @@ __Pyx_RaiseArgtupleInvalid("__init__", 1, 0, 0, PyTuple_GET_SIZE(__pyx_args)); return -1;} if (unlikely(__pyx_kwds) && unlikely(PyDict_Size(__pyx_kwds) > 0) && unlikely(!__Pyx_CheckKeywordStrings(__pyx_kwds, "__init__", 0))) return -1; - /* "iocpsupport.pyx":143 + /* "iocpsupport.pyx":152 * def __init__(self): * cdef HANDLE res * res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) # <<<<<<<<<<<<<< @@ -1143,7 +1156,7 @@ */ __pyx_v_res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0); - /* "iocpsupport.pyx":144 + /* "iocpsupport.pyx":153 * cdef HANDLE res * res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) * if not res: # <<<<<<<<<<<<<< @@ -1153,7 +1166,7 @@ __pyx_t_1 = (!__pyx_v_res); if (__pyx_t_1) { - /* "iocpsupport.pyx":145 + /* "iocpsupport.pyx":154 * res = CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0) * if not res: * raise_error(0, 'CreateIoCompletionPort') # <<<<<<<<<<<<<< @@ -1162,13 +1175,13 @@ */ __pyx_t_2 = ((PyObject *)__pyx_n_s_1); __Pyx_INCREF(__pyx_t_2); - __pyx_f_11iocpsupport_raise_error(0, __pyx_t_2); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 145; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(0, __pyx_t_2); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; goto __pyx_L5; } __pyx_L5:; - /* "iocpsupport.pyx":146 + /* "iocpsupport.pyx":155 * if not res: * raise_error(0, 'CreateIoCompletionPort') * self.port = res # <<<<<<<<<<<<<< @@ -1188,7 +1201,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":148 +/* "iocpsupport.pyx":157 * self.port = res * * def addHandle(self, HANDLE handle, size_t key=0): # <<<<<<<<<<<<<< @@ -1233,7 +1246,7 @@ } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "addHandle") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 148; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "addHandle") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } else { switch (PyTuple_GET_SIZE(__pyx_args)) { @@ -1243,23 +1256,23 @@ default: goto __pyx_L5_argtuple_error; } } - __pyx_v_handle = __Pyx_PyInt_AsSize_t(values[0]); if (unlikely((__pyx_v_handle == (size_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 148; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_handle = __Pyx_PyInt_AsSize_t(values[0]); if (unlikely((__pyx_v_handle == (size_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L3_error;} if (values[1]) { - __pyx_v_key = __Pyx_PyInt_AsSize_t(values[1]); if (unlikely((__pyx_v_key == (size_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 148; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_key = __Pyx_PyInt_AsSize_t(values[1]); if (unlikely((__pyx_v_key == (size_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } else { __pyx_v_key = ((size_t)0); } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("addHandle", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 148; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("addHandle", 0, 1, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("iocpsupport.CompletionPort.addHandle", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":150 + /* "iocpsupport.pyx":159 * def addHandle(self, HANDLE handle, size_t key=0): * cdef HANDLE res * res = CreateIoCompletionPort(handle, self.port, key, 0) # <<<<<<<<<<<<<< @@ -1268,7 +1281,7 @@ */ __pyx_v_res = CreateIoCompletionPort(__pyx_v_handle, ((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port, __pyx_v_key, 0); - /* "iocpsupport.pyx":151 + /* "iocpsupport.pyx":160 * cdef HANDLE res * res = CreateIoCompletionPort(handle, self.port, key, 0) * if not res: # <<<<<<<<<<<<<< @@ -1278,7 +1291,7 @@ __pyx_t_1 = (!__pyx_v_res); if (__pyx_t_1) { - /* "iocpsupport.pyx":152 + /* "iocpsupport.pyx":161 * res = CreateIoCompletionPort(handle, self.port, key, 0) * if not res: * raise_error(0, 'CreateIoCompletionPort') # <<<<<<<<<<<<<< @@ -1287,7 +1300,7 @@ */ __pyx_t_2 = ((PyObject *)__pyx_n_s_1); __Pyx_INCREF(__pyx_t_2); - __pyx_f_11iocpsupport_raise_error(0, __pyx_t_2); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 152; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(0, __pyx_t_2); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; goto __pyx_L6; } @@ -1305,7 +1318,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":154 +/* "iocpsupport.pyx":163 * raise_error(0, 'CreateIoCompletionPort') * * def getEvent(self, long timeout): # <<<<<<<<<<<<<< @@ -1334,7 +1347,7 @@ int __pyx_clineno = 0; __Pyx_RefNannySetupContext("getEvent"); assert(__pyx_arg_timeout); { - __pyx_v_timeout = __Pyx_PyInt_AsLong(__pyx_arg_timeout); if (unlikely((__pyx_v_timeout == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 154; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_timeout = __Pyx_PyInt_AsLong(__pyx_arg_timeout); if (unlikely((__pyx_v_timeout == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -1343,7 +1356,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":160 + /* "iocpsupport.pyx":169 * cdef myOVERLAPPED *ov * * _save = PyEval_SaveThread() # <<<<<<<<<<<<<< @@ -1352,7 +1365,7 @@ */ __pyx_v__save = PyEval_SaveThread(); - /* "iocpsupport.pyx":161 + /* "iocpsupport.pyx":170 * * _save = PyEval_SaveThread() * rc = GetQueuedCompletionStatus(self.port, &bytes, &key, &ov, timeout) # <<<<<<<<<<<<<< @@ -1361,7 +1374,7 @@ */ __pyx_v_rc = GetQueuedCompletionStatus(((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port, (&__pyx_v_bytes), (&__pyx_v_key), ((OVERLAPPED **)(&__pyx_v_ov)), __pyx_v_timeout); - /* "iocpsupport.pyx":162 + /* "iocpsupport.pyx":171 * _save = PyEval_SaveThread() * rc = GetQueuedCompletionStatus(self.port, &bytes, &key, &ov, timeout) * PyEval_RestoreThread(_save) # <<<<<<<<<<<<<< @@ -1370,7 +1383,7 @@ */ PyEval_RestoreThread(__pyx_v__save); - /* "iocpsupport.pyx":164 + /* "iocpsupport.pyx":173 * PyEval_RestoreThread(_save) * * if not rc: # <<<<<<<<<<<<<< @@ -1380,7 +1393,7 @@ __pyx_t_1 = (!__pyx_v_rc); if (__pyx_t_1) { - /* "iocpsupport.pyx":165 + /* "iocpsupport.pyx":174 * * if not rc: * rc = GetLastError() # <<<<<<<<<<<<<< @@ -1392,7 +1405,7 @@ } /*else*/ { - /* "iocpsupport.pyx":167 + /* "iocpsupport.pyx":176 * rc = GetLastError() * else: * rc = 0 # <<<<<<<<<<<<<< @@ -1403,7 +1416,7 @@ } __pyx_L5:; - /* "iocpsupport.pyx":169 + /* "iocpsupport.pyx":178 * rc = 0 * * obj = None # <<<<<<<<<<<<<< @@ -1413,7 +1426,7 @@ __Pyx_INCREF(Py_None); __pyx_v_obj = Py_None; - /* "iocpsupport.pyx":170 + /* "iocpsupport.pyx":179 * * obj = None * if ov: # <<<<<<<<<<<<<< @@ -1423,7 +1436,7 @@ __pyx_t_1 = (__pyx_v_ov != 0); if (__pyx_t_1) { - /* "iocpsupport.pyx":171 + /* "iocpsupport.pyx":180 * obj = None * if ov: * if ov.obj: # <<<<<<<<<<<<<< @@ -1433,7 +1446,7 @@ __pyx_t_1 = (__pyx_v_ov->obj != 0); if (__pyx_t_1) { - /* "iocpsupport.pyx":172 + /* "iocpsupport.pyx":181 * if ov: * if ov.obj: * obj = ov.obj # <<<<<<<<<<<<<< @@ -1444,7 +1457,7 @@ __Pyx_DECREF(__pyx_v_obj); __pyx_v_obj = ((PyObject *)__pyx_v_ov->obj); - /* "iocpsupport.pyx":173 + /* "iocpsupport.pyx":182 * if ov.obj: * obj = ov.obj * Py_DECREF(obj) # we are stealing a reference here # <<<<<<<<<<<<<< @@ -1456,7 +1469,7 @@ } __pyx_L7:; - /* "iocpsupport.pyx":174 + /* "iocpsupport.pyx":183 * obj = ov.obj * Py_DECREF(obj) # we are stealing a reference here * PyMem_Free(ov) # <<<<<<<<<<<<<< @@ -1468,7 +1481,7 @@ } __pyx_L6:; - /* "iocpsupport.pyx":176 + /* "iocpsupport.pyx":185 * PyMem_Free(ov) * * return (rc, bytes, key, obj) # <<<<<<<<<<<<<< @@ -1476,13 +1489,13 @@ * def postEvent(self, unsigned long bytes, size_t key, obj): */ __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = PyLong_FromUnsignedLong(__pyx_v_rc); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyLong_FromUnsignedLong(__pyx_v_rc); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 185; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 185; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __Pyx_PyInt_FromSize_t(__pyx_v_key); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = __Pyx_PyInt_FromSize_t(__pyx_v_key); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 185; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyTuple_New(4); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 185; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_5)); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); @@ -1516,7 +1529,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":178 +/* "iocpsupport.pyx":187 * return (rc, bytes, key, obj) * * def postEvent(self, unsigned long bytes, size_t key, obj): # <<<<<<<<<<<<<< @@ -1562,17 +1575,17 @@ values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__key); if (likely(values[1])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } case 2: values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__obj); if (likely(values[2])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "postEvent") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "postEvent") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { goto __pyx_L5_argtuple_error; @@ -1581,20 +1594,20 @@ values[1] = PyTuple_GET_ITEM(__pyx_args, 1); values[2] = PyTuple_GET_ITEM(__pyx_args, 2); } - __pyx_v_bytes = __Pyx_PyInt_AsUnsignedLong(values[0]); if (unlikely((__pyx_v_bytes == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_key = __Pyx_PyInt_AsSize_t(values[1]); if (unlikely((__pyx_v_key == (size_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_bytes = __Pyx_PyInt_AsUnsignedLong(values[0]); if (unlikely((__pyx_v_bytes == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_key = __Pyx_PyInt_AsSize_t(values[1]); if (unlikely((__pyx_v_key == (size_t)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_v_obj = values[2]; } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("postEvent", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 187; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("iocpsupport.CompletionPort.postEvent", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":182 + /* "iocpsupport.pyx":191 * cdef unsigned long rc * * if obj is not None: # <<<<<<<<<<<<<< @@ -1604,17 +1617,17 @@ __pyx_t_1 = (__pyx_v_obj != Py_None); if (__pyx_t_1) { - /* "iocpsupport.pyx":183 + /* "iocpsupport.pyx":192 * * if obj is not None: * ov = makeOV() # <<<<<<<<<<<<<< * Py_INCREF(obj) # give ov its own reference to obj * ov.obj = obj */ - __pyx_t_2 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 183; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_2 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 192; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ov = __pyx_t_2; - /* "iocpsupport.pyx":184 + /* "iocpsupport.pyx":193 * if obj is not None: * ov = makeOV() * Py_INCREF(obj) # give ov its own reference to obj # <<<<<<<<<<<<<< @@ -1623,7 +1636,7 @@ */ Py_INCREF(__pyx_v_obj); - /* "iocpsupport.pyx":185 + /* "iocpsupport.pyx":194 * ov = makeOV() * Py_INCREF(obj) # give ov its own reference to obj * ov.obj = obj # <<<<<<<<<<<<<< @@ -1635,7 +1648,7 @@ } /*else*/ { - /* "iocpsupport.pyx":187 + /* "iocpsupport.pyx":196 * ov.obj = obj * else: * ov = NULL # <<<<<<<<<<<<<< @@ -1646,35 +1659,66 @@ } __pyx_L6:; - /* "iocpsupport.pyx":189 + /* "iocpsupport.pyx":198 * ov = NULL * * rc = PostQueuedCompletionStatus(self.port, bytes, key, ov) # <<<<<<<<<<<<<< * if not rc: - * raise_error(0, 'PostQueuedCompletionStatus') + * if ov: */ __pyx_v_rc = PostQueuedCompletionStatus(((struct __pyx_obj_11iocpsupport_CompletionPort *)__pyx_v_self)->port, __pyx_v_bytes, __pyx_v_key, ((OVERLAPPED *)__pyx_v_ov)); - /* "iocpsupport.pyx":190 + /* "iocpsupport.pyx":199 * * rc = PostQueuedCompletionStatus(self.port, bytes, key, ov) * if not rc: # <<<<<<<<<<<<<< - * raise_error(0, 'PostQueuedCompletionStatus') - * + * if ov: + * Py_DECREF(obj) */ __pyx_t_1 = (!__pyx_v_rc); if (__pyx_t_1) { - /* "iocpsupport.pyx":191 + /* "iocpsupport.pyx":200 * rc = PostQueuedCompletionStatus(self.port, bytes, key, ov) * if not rc: + * if ov: # <<<<<<<<<<<<<< + * Py_DECREF(obj) + * PyMem_Free(ov) + */ + __pyx_t_1 = (__pyx_v_ov != 0); + if (__pyx_t_1) { + + /* "iocpsupport.pyx":201 + * if not rc: + * if ov: + * Py_DECREF(obj) # <<<<<<<<<<<<<< + * PyMem_Free(ov) + * raise_error(0, 'PostQueuedCompletionStatus') + */ + Py_DECREF(__pyx_v_obj); + + /* "iocpsupport.pyx":202 + * if ov: + * Py_DECREF(obj) + * PyMem_Free(ov) # <<<<<<<<<<<<<< + * raise_error(0, 'PostQueuedCompletionStatus') + * + */ + PyMem_Free(__pyx_v_ov); + goto __pyx_L8; + } + __pyx_L8:; + + /* "iocpsupport.pyx":203 + * Py_DECREF(obj) + * PyMem_Free(ov) * raise_error(0, 'PostQueuedCompletionStatus') # <<<<<<<<<<<<<< * * def __del__(self): */ __pyx_t_3 = ((PyObject *)__pyx_n_s_2); __Pyx_INCREF(__pyx_t_3); - __pyx_f_11iocpsupport_raise_error(0, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 191; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(0, __pyx_t_3); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 203; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; goto __pyx_L7; } @@ -1692,7 +1736,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":193 +/* "iocpsupport.pyx":205 * raise_error(0, 'PostQueuedCompletionStatus') * * def __del__(self): # <<<<<<<<<<<<<< @@ -1706,7 +1750,7 @@ __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("__del__"); - /* "iocpsupport.pyx":194 + /* "iocpsupport.pyx":206 * * def __del__(self): * CloseHandle(self.port) # <<<<<<<<<<<<<< @@ -1721,7 +1765,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":196 +/* "iocpsupport.pyx":208 * CloseHandle(self.port) * * def makesockaddr(object buff): # <<<<<<<<<<<<<< @@ -1744,16 +1788,16 @@ __Pyx_RefNannySetupContext("makesockaddr"); __pyx_self = __pyx_self; - /* "iocpsupport.pyx":200 + /* "iocpsupport.pyx":212 * cdef Py_ssize_t size * * PyObject_AsReadBuffer(buff, &mem_buffer, &size) # <<<<<<<<<<<<<< * # XXX: this should really return the address family as well * return _makesockaddr(mem_buffer, size) */ - __pyx_t_1 = PyObject_AsReadBuffer(__pyx_v_buff, (&__pyx_v_mem_buffer), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 200; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyObject_AsReadBuffer(__pyx_v_buff, (&__pyx_v_mem_buffer), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /* "iocpsupport.pyx":202 + /* "iocpsupport.pyx":214 * PyObject_AsReadBuffer(buff, &mem_buffer, &size) * # XXX: this should really return the address family as well * return _makesockaddr(mem_buffer, size) # <<<<<<<<<<<<<< @@ -1761,7 +1805,7 @@ * cdef object _makesockaddr(sockaddr *addr, Py_ssize_t len): */ __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = __pyx_f_11iocpsupport__makesockaddr(((struct sockaddr *)__pyx_v_mem_buffer), __pyx_v_size); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 202; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __pyx_f_11iocpsupport__makesockaddr(((struct sockaddr *)__pyx_v_mem_buffer), __pyx_v_size); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_r = __pyx_t_2; __pyx_t_2 = 0; @@ -1779,7 +1823,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":204 +/* "iocpsupport.pyx":216 * return _makesockaddr(mem_buffer, size) * * cdef object _makesockaddr(sockaddr *addr, Py_ssize_t len): # <<<<<<<<<<<<<< @@ -1810,7 +1854,7 @@ int __pyx_clineno = 0; __Pyx_RefNannySetupContext("_makesockaddr"); - /* "iocpsupport.pyx":209 + /* "iocpsupport.pyx":221 * cdef char buff[256] * cdef int rc * cdef DWORD buff_size = sizeof(buff) # <<<<<<<<<<<<<< @@ -1819,7 +1863,7 @@ */ __pyx_v_buff_size = (sizeof(__pyx_v_buff)); - /* "iocpsupport.pyx":210 + /* "iocpsupport.pyx":222 * cdef int rc * cdef DWORD buff_size = sizeof(buff) * if not len: # <<<<<<<<<<<<<< @@ -1829,7 +1873,7 @@ __pyx_t_1 = (!__pyx_v_len); if (__pyx_t_1) { - /* "iocpsupport.pyx":211 + /* "iocpsupport.pyx":223 * cdef DWORD buff_size = sizeof(buff) * if not len: * return None # <<<<<<<<<<<<<< @@ -1844,7 +1888,7 @@ } __pyx_L3:; - /* "iocpsupport.pyx":215 + /* "iocpsupport.pyx":227 * sin = addr * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) * elif addr.sa_family == AF_INET6: # <<<<<<<<<<<<<< @@ -1853,7 +1897,7 @@ */ switch (__pyx_v_addr->sa_family) { - /* "iocpsupport.pyx":212 + /* "iocpsupport.pyx":224 * if not len: * return None * if addr.sa_family == AF_INET: # <<<<<<<<<<<<<< @@ -1862,7 +1906,7 @@ */ case AF_INET: - /* "iocpsupport.pyx":213 + /* "iocpsupport.pyx":225 * return None * if addr.sa_family == AF_INET: * sin = addr # <<<<<<<<<<<<<< @@ -1871,7 +1915,7 @@ */ __pyx_v_sin = ((struct sockaddr_in *)__pyx_v_addr); - /* "iocpsupport.pyx":214 + /* "iocpsupport.pyx":226 * if addr.sa_family == AF_INET: * sin = addr * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) # <<<<<<<<<<<<<< @@ -1879,11 +1923,11 @@ * sin6 = addr */ __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = PyString_FromString(inet_ntoa(__pyx_v_sin->sin_addr)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyString_FromString(inet_ntoa(__pyx_v_sin->sin_addr)); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyInt_FromLong(ntohs(__pyx_v_sin->sin_port)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyInt_FromLong(ntohs(__pyx_v_sin->sin_port)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 214; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); @@ -1896,7 +1940,7 @@ goto __pyx_L0; break; - /* "iocpsupport.pyx":215 + /* "iocpsupport.pyx":227 * sin = addr * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) * elif addr.sa_family == AF_INET6: # <<<<<<<<<<<<<< @@ -1905,7 +1949,7 @@ */ case AF_INET6: - /* "iocpsupport.pyx":216 + /* "iocpsupport.pyx":228 * return PyString_FromString(inet_ntoa(sin.sin_addr)), ntohs(sin.sin_port) * elif addr.sa_family == AF_INET6: * sin6 = addr # <<<<<<<<<<<<<< @@ -1914,7 +1958,7 @@ */ __pyx_v_sin6 = ((struct sockaddr_in6 *)__pyx_v_addr); - /* "iocpsupport.pyx":217 + /* "iocpsupport.pyx":229 * elif addr.sa_family == AF_INET6: * sin6 = addr * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) # <<<<<<<<<<<<<< @@ -1923,7 +1967,7 @@ */ __pyx_v_rc = WSAAddressToStringA(__pyx_v_addr, (sizeof(struct sockaddr_in6)), NULL, __pyx_v_buff, (&__pyx_v_buff_size)); - /* "iocpsupport.pyx":218 + /* "iocpsupport.pyx":230 * sin6 = addr * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -1933,7 +1977,7 @@ __pyx_t_1 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_1) { - /* "iocpsupport.pyx":219 + /* "iocpsupport.pyx":231 * rc = WSAAddressToStringA(addr, sizeof(sockaddr_in6), NULL, buff, &buff_size) * if rc == SOCKET_ERROR: * raise_error(0, 'WSAAddressToString') # <<<<<<<<<<<<<< @@ -1942,36 +1986,36 @@ */ __pyx_t_4 = ((PyObject *)__pyx_n_s__WSAAddressToString); __Pyx_INCREF(__pyx_t_4); - __pyx_f_11iocpsupport_raise_error(0, __pyx_t_4); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 219; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(0, __pyx_t_4); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 231; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; goto __pyx_L4; } __pyx_L4:; - /* "iocpsupport.pyx":220 + /* "iocpsupport.pyx":232 * if rc == SOCKET_ERROR: * raise_error(0, 'WSAAddressToString') * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) # <<<<<<<<<<<<<< * host, port = host.rsplit(':', 1) * port = int(port) */ - __pyx_t_4 = PyString_FromString(__pyx_v_buff); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 220; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyString_FromString(__pyx_v_buff); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 232; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); __pyx_t_5 = ntohs(__pyx_v_sin6->sin6_port); __pyx_v_host = __pyx_t_4; __pyx_t_4 = 0; __pyx_v_sa_port = __pyx_t_5; - /* "iocpsupport.pyx":221 + /* "iocpsupport.pyx":233 * raise_error(0, 'WSAAddressToString') * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) * host, port = host.rsplit(':', 1) # <<<<<<<<<<<<<< * port = int(port) * assert host[0] == '[' */ - __pyx_t_4 = PyObject_GetAttr(__pyx_v_host, __pyx_n_s__rsplit); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyObject_GetAttr(__pyx_v_host, __pyx_n_s__rsplit); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_3 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_k_tuple_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_k_tuple_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; if ((likely(PyTuple_CheckExact(__pyx_t_3))) || (PyList_CheckExact(__pyx_t_3))) { @@ -1980,7 +2024,7 @@ if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) { if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2); else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence)); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } __pyx_t_4 = PyTuple_GET_ITEM(sequence, 0); __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1); @@ -1988,7 +2032,7 @@ if (unlikely(PyList_GET_SIZE(sequence) != 2)) { if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2); else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence)); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } __pyx_t_4 = PyList_GET_ITEM(sequence, 0); __pyx_t_2 = PyList_GET_ITEM(sequence, 1); @@ -1998,7 +2042,7 @@ __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; } else { Py_ssize_t index = -1; - __pyx_t_6 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_6 = PyObject_GetIter(__pyx_t_3); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; __pyx_t_7 = Py_TYPE(__pyx_t_6)->tp_iternext; @@ -2006,14 +2050,14 @@ __Pyx_GOTREF(__pyx_t_4); index = 1; __pyx_t_2 = __pyx_t_7(__pyx_t_6); if (unlikely(!__pyx_t_2)) goto __pyx_L5_unpacking_failed; __Pyx_GOTREF(__pyx_t_2); - if (__Pyx_IternextUnpackEndCheck(__pyx_t_7(__pyx_t_6), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (__Pyx_IternextUnpackEndCheck(__pyx_t_7(__pyx_t_6), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; goto __pyx_L6_unpacking_done; __pyx_L5_unpacking_failed:; __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0; if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear(); if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_L6_unpacking_done:; } __Pyx_DECREF(__pyx_v_host); @@ -2022,26 +2066,26 @@ __pyx_v_port = __pyx_t_2; __pyx_t_2 = 0; - /* "iocpsupport.pyx":222 + /* "iocpsupport.pyx":234 * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) * host, port = host.rsplit(':', 1) * port = int(port) # <<<<<<<<<<<<<< * assert host[0] == '[' * assert host[-1] == ']' */ - __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyTuple_New(1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_3)); __Pyx_INCREF(__pyx_v_port); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_v_port); __Pyx_GIVEREF(__pyx_v_port); - __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)(&PyInt_Type))), ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 222; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyObject_Call(((PyObject *)((PyObject*)(&PyInt_Type))), ((PyObject *)__pyx_t_3), NULL); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0; __Pyx_DECREF(__pyx_v_port); __pyx_v_port = __pyx_t_2; __pyx_t_2 = 0; - /* "iocpsupport.pyx":223 + /* "iocpsupport.pyx":235 * host, port = host.rsplit(':', 1) * port = int(port) * assert host[0] == '[' # <<<<<<<<<<<<<< @@ -2049,17 +2093,17 @@ * assert port == sa_port */ #ifndef CYTHON_WITHOUT_ASSERTIONS - __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_host, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_host, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 235; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_2, ((PyObject *)__pyx_kp_s_5), Py_EQ); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_2, ((PyObject *)__pyx_kp_s_5), Py_EQ); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 235; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (unlikely(!__pyx_t_1)) { PyErr_SetNone(PyExc_AssertionError); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 223; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 235; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } #endif - /* "iocpsupport.pyx":224 + /* "iocpsupport.pyx":236 * port = int(port) * assert host[0] == '[' * assert host[-1] == ']' # <<<<<<<<<<<<<< @@ -2067,17 +2111,17 @@ * return host[1:-1], port */ #ifndef CYTHON_WITHOUT_ASSERTIONS - __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_host, -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __Pyx_GetItemInt(__pyx_v_host, -1, sizeof(long), PyInt_FromLong); if (!__pyx_t_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_2, ((PyObject *)__pyx_kp_s_6), Py_EQ); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_PyString_Equals(__pyx_t_2, ((PyObject *)__pyx_kp_s_6), Py_EQ); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; if (unlikely(!__pyx_t_1)) { PyErr_SetNone(PyExc_AssertionError); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 224; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } #endif - /* "iocpsupport.pyx":225 + /* "iocpsupport.pyx":237 * assert host[0] == '[' * assert host[-1] == ']' * assert port == sa_port # <<<<<<<<<<<<<< @@ -2085,20 +2129,20 @@ * else: */ #ifndef CYTHON_WITHOUT_ASSERTIONS - __pyx_t_2 = PyInt_FromLong(__pyx_v_sa_port); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 225; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyInt_FromLong(__pyx_v_sa_port); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyObject_RichCompare(__pyx_v_port, __pyx_t_2, Py_EQ); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 225; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyObject_RichCompare(__pyx_v_port, __pyx_t_2, Py_EQ); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 225; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_PyObject_IsTrue(__pyx_t_3); if (unlikely(__pyx_t_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (unlikely(!__pyx_t_1)) { PyErr_SetNone(PyExc_AssertionError); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 225; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } #endif - /* "iocpsupport.pyx":226 + /* "iocpsupport.pyx":238 * assert host[-1] == ']' * assert port == sa_port * return host[1:-1], port # <<<<<<<<<<<<<< @@ -2106,9 +2150,9 @@ * return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) */ __Pyx_XDECREF(__pyx_r); - __pyx_t_3 = __Pyx_PySequence_GetSlice(__pyx_v_host, 1, -1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = __Pyx_PySequence_GetSlice(__pyx_v_host, 1, -1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); - __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 226; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 238; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_2)); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); __Pyx_GIVEREF(__pyx_t_3); @@ -2122,15 +2166,15 @@ break; default: - /* "iocpsupport.pyx":228 + /* "iocpsupport.pyx":240 * return host[1:-1], port * else: * return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) # <<<<<<<<<<<<<< * - * cdef object fillinetaddr(sockaddr_in *dest, object addr): + * */ __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = PyString_FromStringAndSize(__pyx_v_addr->sa_data, (sizeof(__pyx_v_addr->sa_data))); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 228; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyString_FromStringAndSize(__pyx_v_addr->sa_data, (sizeof(__pyx_v_addr->sa_data))); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 240; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_r = __pyx_t_2; __pyx_t_2 = 0; @@ -2155,8 +2199,8 @@ return __pyx_r; } -/* "iocpsupport.pyx":230 - * return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) +/* "iocpsupport.pyx":243 + * * * cdef object fillinetaddr(sockaddr_in *dest, object addr): # <<<<<<<<<<<<<< * cdef unsigned short port @@ -2182,7 +2226,7 @@ int __pyx_clineno = 0; __Pyx_RefNannySetupContext("fillinetaddr"); - /* "iocpsupport.pyx":234 + /* "iocpsupport.pyx":247 * cdef unsigned long res * cdef char *hoststr * host, port = addr # <<<<<<<<<<<<<< @@ -2195,7 +2239,7 @@ if (unlikely(PyTuple_GET_SIZE(sequence) != 2)) { if (PyTuple_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2); else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence)); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0); __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1); @@ -2203,7 +2247,7 @@ if (unlikely(PyList_GET_SIZE(sequence) != 2)) { if (PyList_GET_SIZE(sequence) > 2) __Pyx_RaiseTooManyValuesError(2); else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence)); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L1_error;} } __pyx_t_1 = PyList_GET_ITEM(sequence, 0); __pyx_t_2 = PyList_GET_ITEM(sequence, 1); @@ -2212,40 +2256,40 @@ __Pyx_INCREF(__pyx_t_2); } else { Py_ssize_t index = -1; - __pyx_t_3 = PyObject_GetIter(__pyx_v_addr); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyObject_GetIter(__pyx_v_addr); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __pyx_t_4 = Py_TYPE(__pyx_t_3)->tp_iternext; index = 0; __pyx_t_1 = __pyx_t_4(__pyx_t_3); if (unlikely(!__pyx_t_1)) goto __pyx_L3_unpacking_failed; __Pyx_GOTREF(__pyx_t_1); index = 1; __pyx_t_2 = __pyx_t_4(__pyx_t_3); if (unlikely(!__pyx_t_2)) goto __pyx_L3_unpacking_failed; __Pyx_GOTREF(__pyx_t_2); - if (__Pyx_IternextUnpackEndCheck(__pyx_t_4(__pyx_t_3), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (__Pyx_IternextUnpackEndCheck(__pyx_t_4(__pyx_t_3), 2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; goto __pyx_L4_unpacking_done; __pyx_L3_unpacking_failed:; __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear(); if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_L4_unpacking_done:; } - __pyx_t_5 = __Pyx_PyInt_AsUnsignedShort(__pyx_t_2); if (unlikely((__pyx_t_5 == (unsigned short)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 234; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = __Pyx_PyInt_AsUnsignedShort(__pyx_t_2); if (unlikely((__pyx_t_5 == (unsigned short)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __pyx_v_host = __pyx_t_1; __pyx_t_1 = 0; __pyx_v_port = __pyx_t_5; - /* "iocpsupport.pyx":236 + /* "iocpsupport.pyx":249 * host, port = addr * * hoststr = PyString_AsString(host) # <<<<<<<<<<<<<< * res = inet_addr(hoststr) * if res == INADDR_ANY: */ - __pyx_t_6 = PyString_AsString(__pyx_v_host); if (unlikely(__pyx_t_6 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 236; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_6 = PyString_AsString(__pyx_v_host); if (unlikely(__pyx_t_6 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 249; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_hoststr = __pyx_t_6; - /* "iocpsupport.pyx":237 + /* "iocpsupport.pyx":250 * * hoststr = PyString_AsString(host) * res = inet_addr(hoststr) # <<<<<<<<<<<<<< @@ -2254,7 +2298,7 @@ */ __pyx_v_res = inet_addr(__pyx_v_hoststr); - /* "iocpsupport.pyx":238 + /* "iocpsupport.pyx":251 * hoststr = PyString_AsString(host) * res = inet_addr(hoststr) * if res == INADDR_ANY: # <<<<<<<<<<<<<< @@ -2264,7 +2308,7 @@ __pyx_t_7 = (__pyx_v_res == INADDR_ANY); if (__pyx_t_7) { - /* "iocpsupport.pyx":239 + /* "iocpsupport.pyx":252 * res = inet_addr(hoststr) * if res == INADDR_ANY: * raise ValueError, 'invalid IP address' # <<<<<<<<<<<<<< @@ -2272,12 +2316,12 @@ * */ __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_7), 0, 0); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 239; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 252; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L5; } __pyx_L5:; - /* "iocpsupport.pyx":240 + /* "iocpsupport.pyx":253 * if res == INADDR_ANY: * raise ValueError, 'invalid IP address' * dest.sin_addr.s_addr = res # <<<<<<<<<<<<<< @@ -2286,12 +2330,12 @@ */ __pyx_v_dest->sin_addr.s_addr = __pyx_v_res; - /* "iocpsupport.pyx":242 + /* "iocpsupport.pyx":255 * dest.sin_addr.s_addr = res * * dest.sin_port = htons(port) # <<<<<<<<<<<<<< * - * def AllocateReadBuffer(int size): + * */ __pyx_v_dest->sin_port = htons(__pyx_v_port); @@ -2310,8 +2354,258 @@ return __pyx_r; } -/* "iocpsupport.pyx":244 - * dest.sin_port = htons(port) +/* "iocpsupport.pyx":258 + * + * + * cdef object fillinet6addr(sockaddr_in6 *dest, object addr): # <<<<<<<<<<<<<< + * cdef unsigned short port + * cdef unsigned long res + */ + +static PyObject *__pyx_f_11iocpsupport_fillinet6addr(struct sockaddr_in6 *__pyx_v_dest, PyObject *__pyx_v_addr) { + unsigned short __pyx_v_port; + char *__pyx_v_hoststr; + int __pyx_v_addrlen; + PyObject *__pyx_v_host = NULL; + PyObject *__pyx_v_flow = NULL; + PyObject *__pyx_v_scope = NULL; + int __pyx_v_parseresult; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + PyObject *(*__pyx_t_6)(PyObject *); + unsigned short __pyx_t_7; + char *__pyx_t_8; + int __pyx_t_9; + unsigned long __pyx_t_10; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("fillinet6addr"); + + /* "iocpsupport.pyx":262 + * cdef unsigned long res + * cdef char *hoststr + * cdef int addrlen = sizeof(sockaddr_in6) # <<<<<<<<<<<<<< + * host, port, flow, scope = addr + * host = host.split("%")[0] # remove scope ID, if any + */ + __pyx_v_addrlen = (sizeof(struct sockaddr_in6)); + + /* "iocpsupport.pyx":263 + * cdef char *hoststr + * cdef int addrlen = sizeof(sockaddr_in6) + * host, port, flow, scope = addr # <<<<<<<<<<<<<< + * host = host.split("%")[0] # remove scope ID, if any + * + */ + if ((likely(PyTuple_CheckExact(__pyx_v_addr))) || (PyList_CheckExact(__pyx_v_addr))) { + PyObject* sequence = __pyx_v_addr; + if (likely(PyTuple_CheckExact(sequence))) { + if (unlikely(PyTuple_GET_SIZE(sequence) != 4)) { + if (PyTuple_GET_SIZE(sequence) > 4) __Pyx_RaiseTooManyValuesError(4); + else __Pyx_RaiseNeedMoreValuesError(PyTuple_GET_SIZE(sequence)); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + } + __pyx_t_1 = PyTuple_GET_ITEM(sequence, 0); + __pyx_t_2 = PyTuple_GET_ITEM(sequence, 1); + __pyx_t_3 = PyTuple_GET_ITEM(sequence, 2); + __pyx_t_4 = PyTuple_GET_ITEM(sequence, 3); + } else { + if (unlikely(PyList_GET_SIZE(sequence) != 4)) { + if (PyList_GET_SIZE(sequence) > 4) __Pyx_RaiseTooManyValuesError(4); + else __Pyx_RaiseNeedMoreValuesError(PyList_GET_SIZE(sequence)); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + } + __pyx_t_1 = PyList_GET_ITEM(sequence, 0); + __pyx_t_2 = PyList_GET_ITEM(sequence, 1); + __pyx_t_3 = PyList_GET_ITEM(sequence, 2); + __pyx_t_4 = PyList_GET_ITEM(sequence, 3); + } + __Pyx_INCREF(__pyx_t_1); + __Pyx_INCREF(__pyx_t_2); + __Pyx_INCREF(__pyx_t_3); + __Pyx_INCREF(__pyx_t_4); + } else { + Py_ssize_t index = -1; + __pyx_t_5 = PyObject_GetIter(__pyx_v_addr); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_5); + __pyx_t_6 = Py_TYPE(__pyx_t_5)->tp_iternext; + index = 0; __pyx_t_1 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_1)) goto __pyx_L3_unpacking_failed; + __Pyx_GOTREF(__pyx_t_1); + index = 1; __pyx_t_2 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_2)) goto __pyx_L3_unpacking_failed; + __Pyx_GOTREF(__pyx_t_2); + index = 2; __pyx_t_3 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_3)) goto __pyx_L3_unpacking_failed; + __Pyx_GOTREF(__pyx_t_3); + index = 3; __pyx_t_4 = __pyx_t_6(__pyx_t_5); if (unlikely(!__pyx_t_4)) goto __pyx_L3_unpacking_failed; + __Pyx_GOTREF(__pyx_t_4); + if (__Pyx_IternextUnpackEndCheck(__pyx_t_6(__pyx_t_5), 4) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + goto __pyx_L4_unpacking_done; + __pyx_L3_unpacking_failed:; + __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0; + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) PyErr_Clear(); + if (!PyErr_Occurred()) __Pyx_RaiseNeedMoreValuesError(index); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_L4_unpacking_done:; + } + __pyx_t_7 = __Pyx_PyInt_AsUnsignedShort(__pyx_t_2); if (unlikely((__pyx_t_7 == (unsigned short)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 263; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; + __pyx_v_host = __pyx_t_1; + __pyx_t_1 = 0; + __pyx_v_port = __pyx_t_7; + __pyx_v_flow = __pyx_t_3; + __pyx_t_3 = 0; + __pyx_v_scope = __pyx_t_4; + __pyx_t_4 = 0; + + /* "iocpsupport.pyx":264 + * cdef int addrlen = sizeof(sockaddr_in6) + * host, port, flow, scope = addr + * host = host.split("%")[0] # remove scope ID, if any # <<<<<<<<<<<<<< + * + * hoststr = PyString_AsString(host) + */ + __pyx_t_4 = PyObject_GetAttr(__pyx_v_host, __pyx_n_s__split); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_3 = PyObject_Call(__pyx_t_4, ((PyObject *)__pyx_k_tuple_9), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + __pyx_t_4 = __Pyx_GetItemInt(__pyx_t_3, 0, sizeof(long), PyInt_FromLong); if (!__pyx_t_4) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_DECREF(__pyx_v_host); + __pyx_v_host = __pyx_t_4; + __pyx_t_4 = 0; + + /* "iocpsupport.pyx":266 + * host = host.split("%")[0] # remove scope ID, if any + * + * hoststr = PyString_AsString(host) # <<<<<<<<<<<<<< + * cdef int parseresult = WSAStringToAddressA(hoststr, AF_INET6, NULL, + * dest, &addrlen) + */ + __pyx_t_8 = PyString_AsString(__pyx_v_host); if (unlikely(__pyx_t_8 == NULL)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 266; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_v_hoststr = __pyx_t_8; + + /* "iocpsupport.pyx":268 + * hoststr = PyString_AsString(host) + * cdef int parseresult = WSAStringToAddressA(hoststr, AF_INET6, NULL, + * dest, &addrlen) # <<<<<<<<<<<<<< + * if parseresult == SOCKET_ERROR: + * raise ValueError, 'invalid IPv6 address %r' % (host,) + */ + __pyx_v_parseresult = WSAStringToAddressA(__pyx_v_hoststr, AF_INET6, NULL, ((struct sockaddr *)__pyx_v_dest), (&__pyx_v_addrlen)); + + /* "iocpsupport.pyx":269 + * cdef int parseresult = WSAStringToAddressA(hoststr, AF_INET6, NULL, + * dest, &addrlen) + * if parseresult == SOCKET_ERROR: # <<<<<<<<<<<<<< + * raise ValueError, 'invalid IPv6 address %r' % (host,) + * if parseresult != 0: + */ + __pyx_t_9 = (__pyx_v_parseresult == SOCKET_ERROR); + if (__pyx_t_9) { + + /* "iocpsupport.pyx":270 + * dest, &addrlen) + * if parseresult == SOCKET_ERROR: + * raise ValueError, 'invalid IPv6 address %r' % (host,) # <<<<<<<<<<<<<< + * if parseresult != 0: + * raise RuntimeError, 'undefined error occurred during address parsing' + */ + __pyx_t_4 = PyTuple_New(1); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_4)); + __Pyx_INCREF(__pyx_v_host); + PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_v_host); + __Pyx_GIVEREF(__pyx_v_host); + __pyx_t_3 = PyNumber_Remainder(((PyObject *)__pyx_kp_s_10), ((PyObject *)__pyx_t_4)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_3)); + __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_t_3), 0, 0); + __Pyx_DECREF(((PyObject *)__pyx_t_3)); __pyx_t_3 = 0; + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + goto __pyx_L5; + } + __pyx_L5:; + + /* "iocpsupport.pyx":271 + * if parseresult == SOCKET_ERROR: + * raise ValueError, 'invalid IPv6 address %r' % (host,) + * if parseresult != 0: # <<<<<<<<<<<<<< + * raise RuntimeError, 'undefined error occurred during address parsing' + * # sin6_host field was handled by WSAStringToAddress + */ + __pyx_t_9 = (__pyx_v_parseresult != 0); + if (__pyx_t_9) { + + /* "iocpsupport.pyx":272 + * raise ValueError, 'invalid IPv6 address %r' % (host,) + * if parseresult != 0: + * raise RuntimeError, 'undefined error occurred during address parsing' # <<<<<<<<<<<<<< + * # sin6_host field was handled by WSAStringToAddress + * dest.sin6_port = htons(port) + */ + __Pyx_Raise(__pyx_builtin_RuntimeError, ((PyObject *)__pyx_kp_s_11), 0, 0); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 272; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + goto __pyx_L6; + } + __pyx_L6:; + + /* "iocpsupport.pyx":274 + * raise RuntimeError, 'undefined error occurred during address parsing' + * # sin6_host field was handled by WSAStringToAddress + * dest.sin6_port = htons(port) # <<<<<<<<<<<<<< + * dest.sin6_flowinfo = flow + * dest.sin6_scope_id = scope + */ + __pyx_v_dest->sin6_port = htons(__pyx_v_port); + + /* "iocpsupport.pyx":275 + * # sin6_host field was handled by WSAStringToAddress + * dest.sin6_port = htons(port) + * dest.sin6_flowinfo = flow # <<<<<<<<<<<<<< + * dest.sin6_scope_id = scope + * + */ + __pyx_t_10 = __Pyx_PyInt_AsUnsignedLong(__pyx_v_flow); if (unlikely((__pyx_t_10 == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 275; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_v_dest->sin6_flowinfo = __pyx_t_10; + + /* "iocpsupport.pyx":276 + * dest.sin6_port = htons(port) + * dest.sin6_flowinfo = flow + * dest.sin6_scope_id = scope # <<<<<<<<<<<<<< + * + * + */ + __pyx_t_10 = __Pyx_PyInt_AsUnsignedLong(__pyx_v_scope); if (unlikely((__pyx_t_10 == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_v_dest->sin6_scope_id = __pyx_t_10; + + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("iocpsupport.fillinet6addr", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_host); + __Pyx_XDECREF(__pyx_v_flow); + __Pyx_XDECREF(__pyx_v_scope); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "iocpsupport.pyx":279 + * * * def AllocateReadBuffer(int size): # <<<<<<<<<<<<<< * return PyBuffer_New(size) @@ -2331,7 +2625,7 @@ __Pyx_RefNannySetupContext("AllocateReadBuffer"); __pyx_self = __pyx_self; assert(__pyx_arg_size); { - __pyx_v_size = __Pyx_PyInt_AsInt(__pyx_arg_size); if (unlikely((__pyx_v_size == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_size = __Pyx_PyInt_AsInt(__pyx_arg_size); if (unlikely((__pyx_v_size == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 279; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -2340,7 +2634,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":245 + /* "iocpsupport.pyx":280 * * def AllocateReadBuffer(int size): * return PyBuffer_New(size) # <<<<<<<<<<<<<< @@ -2348,7 +2642,7 @@ * def maxAddrLen(long s): */ __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = PyBuffer_New(__pyx_v_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 245; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyBuffer_New(__pyx_v_size); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 280; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; @@ -2366,7 +2660,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":247 +/* "iocpsupport.pyx":282 * return PyBuffer_New(size) * * def maxAddrLen(long s): # <<<<<<<<<<<<<< @@ -2391,7 +2685,7 @@ __Pyx_RefNannySetupContext("maxAddrLen"); __pyx_self = __pyx_self; assert(__pyx_arg_s); { - __pyx_v_s = __Pyx_PyInt_AsLong(__pyx_arg_s); if (unlikely((__pyx_v_s == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_s = __Pyx_PyInt_AsLong(__pyx_arg_s); if (unlikely((__pyx_v_s == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 282; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L3_error:; @@ -2400,7 +2694,7 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "iocpsupport.pyx":251 + /* "iocpsupport.pyx":286 * cdef int size, rc * * size = sizeof(wsa_pi) # <<<<<<<<<<<<<< @@ -2409,7 +2703,7 @@ */ __pyx_v_size = (sizeof(__pyx_v_wsa_pi)); - /* "iocpsupport.pyx":252 + /* "iocpsupport.pyx":287 * * size = sizeof(wsa_pi) * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) # <<<<<<<<<<<<<< @@ -2418,7 +2712,7 @@ */ __pyx_v_rc = getsockopt(__pyx_v_s, SOL_SOCKET, SO_PROTOCOL_INFO, ((char *)(&__pyx_v_wsa_pi)), (&__pyx_v_size)); - /* "iocpsupport.pyx":253 + /* "iocpsupport.pyx":288 * size = sizeof(wsa_pi) * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -2428,7 +2722,7 @@ __pyx_t_1 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_1) { - /* "iocpsupport.pyx":254 + /* "iocpsupport.pyx":289 * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) * if rc == SOCKET_ERROR: * raise_error(WSAGetLastError(), 'getsockopt') # <<<<<<<<<<<<<< @@ -2437,13 +2731,13 @@ */ __pyx_t_2 = ((PyObject *)__pyx_n_s__getsockopt); __Pyx_INCREF(__pyx_t_2); - __pyx_f_11iocpsupport_raise_error(WSAGetLastError(), __pyx_t_2); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 254; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(WSAGetLastError(), __pyx_t_2); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 289; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; goto __pyx_L5; } __pyx_L5:; - /* "iocpsupport.pyx":255 + /* "iocpsupport.pyx":290 * if rc == SOCKET_ERROR: * raise_error(WSAGetLastError(), 'getsockopt') * return wsa_pi.iMaxSockAddr # <<<<<<<<<<<<<< @@ -2451,7 +2745,7 @@ * cdef int getAddrFamily(SOCKET s) except *: */ __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = PyInt_FromLong(__pyx_v_wsa_pi.iMaxSockAddr); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 255; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyInt_FromLong(__pyx_v_wsa_pi.iMaxSockAddr); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 290; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); __pyx_r = __pyx_t_2; __pyx_t_2 = 0; @@ -2469,7 +2763,7 @@ return __pyx_r; } -/* "iocpsupport.pyx":257 +/* "iocpsupport.pyx":292 * return wsa_pi.iMaxSockAddr * * cdef int getAddrFamily(SOCKET s) except *: # <<<<<<<<<<<<<< @@ -2490,7 +2784,7 @@ int __pyx_clineno = 0; __Pyx_RefNannySetupContext("getAddrFamily"); - /* "iocpsupport.pyx":261 + /* "iocpsupport.pyx":296 * cdef int size, rc * * size = sizeof(wsa_pi) # <<<<<<<<<<<<<< @@ -2499,7 +2793,7 @@ */ __pyx_v_size = (sizeof(__pyx_v_wsa_pi)); - /* "iocpsupport.pyx":262 + /* "iocpsupport.pyx":297 * * size = sizeof(wsa_pi) * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) # <<<<<<<<<<<<<< @@ -2508,7 +2802,7 @@ */ __pyx_v_rc = getsockopt(__pyx_v_s, SOL_SOCKET, SO_PROTOCOL_INFO, ((char *)(&__pyx_v_wsa_pi)), (&__pyx_v_size)); - /* "iocpsupport.pyx":263 + /* "iocpsupport.pyx":298 * size = sizeof(wsa_pi) * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -2518,7 +2812,7 @@ __pyx_t_1 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_1) { - /* "iocpsupport.pyx":264 + /* "iocpsupport.pyx":299 * rc = getsockopt(s, SOL_SOCKET, SO_PROTOCOL_INFO, &wsa_pi, &size) * if rc == SOCKET_ERROR: * raise_error(WSAGetLastError(), 'getsockopt') # <<<<<<<<<<<<<< @@ -2527,13 +2821,13 @@ */ __pyx_t_2 = ((PyObject *)__pyx_n_s__getsockopt); __Pyx_INCREF(__pyx_t_2); - __pyx_f_11iocpsupport_raise_error(WSAGetLastError(), __pyx_t_2); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_f_11iocpsupport_raise_error(WSAGetLastError(), __pyx_t_2); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 299; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; goto __pyx_L3; } __pyx_L3:; - /* "iocpsupport.pyx":265 + /* "iocpsupport.pyx":300 * if rc == SOCKET_ERROR: * raise_error(WSAGetLastError(), 'getsockopt') * return wsa_pi.iAddressFamily # <<<<<<<<<<<<<< @@ -2714,7 +3008,7 @@ * if not rc: * rc = WSAGetLastError() # <<<<<<<<<<<<<< * if rc != ERROR_IO_PENDING: - * return rc + * PyMem_Free(ov) */ __pyx_v_rc = WSAGetLastError(); @@ -2722,8 +3016,8 @@ * if not rc: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< + * PyMem_Free(ov) * return rc - * */ __pyx_t_3 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_3) { @@ -2731,12 +3025,21 @@ /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":27 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) # <<<<<<<<<<<<<< + * return rc + * + */ + PyMem_Free(__pyx_v_ov); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":28 + * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) * return rc # <<<<<<<<<<<<<< * * # operation is in progress */ __Pyx_XDECREF(__pyx_r); - __pyx_t_4 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); __pyx_r = __pyx_t_4; __pyx_t_4 = 0; @@ -2748,7 +3051,7 @@ } __pyx_L7:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":30 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":31 * * # operation is in progress * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -2757,7 +3060,7 @@ */ Py_XINCREF(__pyx_v_obj); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":31 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":32 * # operation is in progress * Py_XINCREF(obj) * return 0 # <<<<<<<<<<<<<< @@ -2781,7 +3084,7 @@ return __pyx_r; } -/* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":33 +/* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":34 * return 0 * * def get_accept_addrs(long s, object buff): # <<<<<<<<<<<<<< @@ -2833,11 +3136,11 @@ values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__buff); if (likely(values[1])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("get_accept_addrs", 1, 2, 2, 1); {__pyx_filename = __pyx_f[1]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("get_accept_addrs", 1, 2, 2, 1); {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "get_accept_addrs") < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "get_accept_addrs") < 0)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { goto __pyx_L5_argtuple_error; @@ -2845,28 +3148,28 @@ values[0] = PyTuple_GET_ITEM(__pyx_args, 0); values[1] = PyTuple_GET_ITEM(__pyx_args, 1); } - __pyx_v_s = __Pyx_PyInt_AsLong(values[0]); if (unlikely((__pyx_v_s == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_s = __Pyx_PyInt_AsLong(values[0]); if (unlikely((__pyx_v_s == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_v_buff = values[1]; } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("get_accept_addrs", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[1]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("get_accept_addrs", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("iocpsupport.get_accept_addrs", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":40 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":41 * cdef sockaddr *localaddr, *remoteaddr * * PyObject_AsReadBuffer(buff, &mem_buffer, &size) # <<<<<<<<<<<<<< * * lpGetAcceptExSockaddrs(mem_buffer, 0, size / 2, size / 2, */ - __pyx_t_1 = PyObject_AsReadBuffer(__pyx_v_buff, (&__pyx_v_mem_buffer), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyObject_AsReadBuffer(__pyx_v_buff, (&__pyx_v_mem_buffer), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":43 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":44 * * lpGetAcceptExSockaddrs(mem_buffer, 0, size / 2, size / 2, * &localaddr, &locallen, &remoteaddr, &remotelen) # <<<<<<<<<<<<<< @@ -2875,20 +3178,20 @@ */ lpGetAcceptExSockaddrs(__pyx_v_mem_buffer, 0, (((__pyx_t_11iocpsupport_DWORD)__pyx_v_size) / 2), (((__pyx_t_11iocpsupport_DWORD)__pyx_v_size) / 2), (&__pyx_v_localaddr), (&__pyx_v_locallen), (&__pyx_v_remoteaddr), (&__pyx_v_remotelen)); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":44 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":45 * lpGetAcceptExSockaddrs(mem_buffer, 0, size / 2, size / 2, * &localaddr, &locallen, &remoteaddr, &remotelen) * return remoteaddr.sa_family, _makesockaddr(localaddr, locallen), _makesockaddr(remoteaddr, remotelen) # <<<<<<<<<<<<<< * */ __Pyx_XDECREF(__pyx_r); - __pyx_t_2 = PyInt_FromLong(__pyx_v_remoteaddr->sa_family); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyInt_FromLong(__pyx_v_remoteaddr->sa_family); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = __pyx_f_11iocpsupport__makesockaddr(__pyx_v_localaddr, __pyx_v_locallen); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = __pyx_f_11iocpsupport__makesockaddr(__pyx_v_localaddr, __pyx_v_locallen); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = __pyx_f_11iocpsupport__makesockaddr(__pyx_v_remoteaddr, __pyx_v_remotelen); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = __pyx_f_11iocpsupport__makesockaddr(__pyx_v_remoteaddr, __pyx_v_remotelen); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 44; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyTuple_New(3); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 45; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_5)); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); @@ -2936,7 +3239,10 @@ int __pyx_v_family; int __pyx_v_rc; struct __pyx_t_11iocpsupport_myOVERLAPPED *__pyx_v_ov; - struct sockaddr __pyx_v_name; + struct sockaddr_in __pyx_v_ipv4_name; + struct sockaddr_in6 __pyx_v_ipv6_name; + struct sockaddr *__pyx_v_name; + int __pyx_v_namelen; PyObject *__pyx_r = NULL; __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; @@ -3003,99 +3309,163 @@ return NULL; __pyx_L4_argument_unpacking_done:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":13 - * cdef sockaddr name + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":16 + * cdef int namelen * * if not have_connectex: # <<<<<<<<<<<<<< * raise ValueError, 'ConnectEx is not available on this system' * */ - __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__have_connectex); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__have_connectex); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __Pyx_PyObject_IsTrue(__pyx_t_1); if (unlikely(__pyx_t_2 < 0)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; __pyx_t_3 = (!__pyx_t_2); if (__pyx_t_3) { - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":14 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":17 * * if not have_connectex: * raise ValueError, 'ConnectEx is not available on this system' # <<<<<<<<<<<<<< * * family = getAddrFamily(s) */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_8), 0, 0); - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 14; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_12), 0, 0); + {__pyx_filename = __pyx_f[2]; __pyx_lineno = 17; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":16 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":19 * raise ValueError, 'ConnectEx is not available on this system' * * family = getAddrFamily(s) # <<<<<<<<<<<<<< * if family == AF_INET: - * fillinetaddr(&name, addr) + * name = &ipv4_name */ - __pyx_t_4 = __pyx_f_11iocpsupport_getAddrFamily(__pyx_v_s); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 16; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = __pyx_f_11iocpsupport_getAddrFamily(__pyx_v_s); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 19; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_family = __pyx_t_4; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":17 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":24 + * namelen = sizeof(ipv4_name) + * fillinetaddr(&ipv4_name, addr) + * elif family == AF_INET6: # <<<<<<<<<<<<<< + * name = &ipv6_name + * namelen = sizeof(ipv6_name) + */ + switch (__pyx_v_family) { + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":20 * * family = getAddrFamily(s) * if family == AF_INET: # <<<<<<<<<<<<<< - * fillinetaddr(&name, addr) - * else: + * name = &ipv4_name + * namelen = sizeof(ipv4_name) */ - __pyx_t_3 = (__pyx_v_family == AF_INET); - if (__pyx_t_3) { + case AF_INET: - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":18 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":21 * family = getAddrFamily(s) * if family == AF_INET: - * fillinetaddr(&name, addr) # <<<<<<<<<<<<<< + * name = &ipv4_name # <<<<<<<<<<<<<< + * namelen = sizeof(ipv4_name) + * fillinetaddr(&ipv4_name, addr) + */ + __pyx_v_name = ((struct sockaddr *)(&__pyx_v_ipv4_name)); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":22 + * if family == AF_INET: + * name = &ipv4_name + * namelen = sizeof(ipv4_name) # <<<<<<<<<<<<<< + * fillinetaddr(&ipv4_name, addr) + * elif family == AF_INET6: + */ + __pyx_v_namelen = (sizeof(__pyx_v_ipv4_name)); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":23 + * name = &ipv4_name + * namelen = sizeof(ipv4_name) + * fillinetaddr(&ipv4_name, addr) # <<<<<<<<<<<<<< + * elif family == AF_INET6: + * name = &ipv6_name + */ + __pyx_t_1 = __pyx_f_11iocpsupport_fillinetaddr((&__pyx_v_ipv4_name), __pyx_v_addr); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + break; + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":24 + * namelen = sizeof(ipv4_name) + * fillinetaddr(&ipv4_name, addr) + * elif family == AF_INET6: # <<<<<<<<<<<<<< + * name = &ipv6_name + * namelen = sizeof(ipv6_name) + */ + case AF_INET6: + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":25 + * fillinetaddr(&ipv4_name, addr) + * elif family == AF_INET6: + * name = &ipv6_name # <<<<<<<<<<<<<< + * namelen = sizeof(ipv6_name) + * fillinet6addr(&ipv6_name, addr) + */ + __pyx_v_name = ((struct sockaddr *)(&__pyx_v_ipv6_name)); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":26 + * elif family == AF_INET6: + * name = &ipv6_name + * namelen = sizeof(ipv6_name) # <<<<<<<<<<<<<< + * fillinet6addr(&ipv6_name, addr) + * else: + */ + __pyx_v_namelen = (sizeof(__pyx_v_ipv6_name)); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":27 + * name = &ipv6_name + * namelen = sizeof(ipv6_name) + * fillinet6addr(&ipv6_name, addr) # <<<<<<<<<<<<<< * else: * raise ValueError, 'unsupported address family' */ - __pyx_t_1 = __pyx_f_11iocpsupport_fillinetaddr(((struct sockaddr_in *)(&__pyx_v_name)), __pyx_v_addr); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 18; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __pyx_f_11iocpsupport_fillinet6addr((&__pyx_v_ipv6_name), __pyx_v_addr); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - goto __pyx_L7; - } - /*else*/ { + break; + default: - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":20 - * fillinetaddr(&name, addr) + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":29 + * fillinet6addr(&ipv6_name, addr) * else: * raise ValueError, 'unsupported address family' # <<<<<<<<<<<<<< * name.sa_family = family * */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_9), 0, 0); - {__pyx_filename = __pyx_f[2]; __pyx_lineno = 20; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_13), 0, 0); + {__pyx_filename = __pyx_f[2]; __pyx_lineno = 29; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + break; } - __pyx_L7:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":21 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":30 * else: * raise ValueError, 'unsupported address family' * name.sa_family = family # <<<<<<<<<<<<<< * * ov = makeOV() */ - __pyx_v_name.sa_family = __pyx_v_family; + __pyx_v_name->sa_family = __pyx_v_family; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":23 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":32 * name.sa_family = family * * ov = makeOV() # <<<<<<<<<<<<<< * if obj is not None: * ov.obj = obj */ - __pyx_t_5 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_5 == NULL)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 23; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_5 == NULL)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ov = __pyx_t_5; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":24 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":33 * * ov = makeOV() * if obj is not None: # <<<<<<<<<<<<<< @@ -3105,29 +3475,29 @@ __pyx_t_3 = (__pyx_v_obj != Py_None); if (__pyx_t_3) { - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":25 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":34 * ov = makeOV() * if obj is not None: * ov.obj = obj # <<<<<<<<<<<<<< * - * rc = lpConnectEx(s, &name, sizeof(name), NULL, 0, NULL, ov) + * rc = lpConnectEx(s, name, namelen, NULL, 0, NULL, ov) */ __pyx_v_ov->obj = ((struct PyObject *)__pyx_v_obj); - goto __pyx_L8; + goto __pyx_L7; } - __pyx_L8:; + __pyx_L7:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":27 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":36 * ov.obj = obj * - * rc = lpConnectEx(s, &name, sizeof(name), NULL, 0, NULL, ov) # <<<<<<<<<<<<<< + * rc = lpConnectEx(s, name, namelen, NULL, 0, NULL, ov) # <<<<<<<<<<<<<< * * if not rc: */ - __pyx_v_rc = lpConnectEx(__pyx_v_s, (&__pyx_v_name), (sizeof(__pyx_v_name)), NULL, 0, NULL, ((OVERLAPPED *)__pyx_v_ov)); + __pyx_v_rc = lpConnectEx(__pyx_v_s, __pyx_v_name, __pyx_v_namelen, NULL, 0, NULL, ((OVERLAPPED *)__pyx_v_ov)); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":29 - * rc = lpConnectEx(s, &name, sizeof(name), NULL, 0, NULL, ov) + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":38 + * rc = lpConnectEx(s, name, namelen, NULL, 0, NULL, ov) * * if not rc: # <<<<<<<<<<<<<< * rc = WSAGetLastError() @@ -3136,46 +3506,55 @@ __pyx_t_3 = (!__pyx_v_rc); if (__pyx_t_3) { - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":30 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":39 * * if not rc: * rc = WSAGetLastError() # <<<<<<<<<<<<<< * if rc != ERROR_IO_PENDING: - * return rc + * PyMem_Free(ov) */ __pyx_v_rc = WSAGetLastError(); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":31 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":40 * if not rc: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< + * PyMem_Free(ov) * return rc - * */ __pyx_t_3 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_3) { - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":32 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":41 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) # <<<<<<<<<<<<<< + * return rc + * + */ + PyMem_Free(__pyx_v_ov); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":42 + * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) * return rc # <<<<<<<<<<<<<< * * # operation is in progress */ __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 32; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[2]; __pyx_lineno = 42; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; goto __pyx_L0; - goto __pyx_L10; + goto __pyx_L9; } - __pyx_L10:; - goto __pyx_L9; + __pyx_L9:; + goto __pyx_L8; } - __pyx_L9:; + __pyx_L8:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":35 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":45 * * # operation is in progress * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -3184,7 +3563,7 @@ */ Py_XINCREF(__pyx_v_obj); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":36 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":46 * # operation is in progress * Py_XINCREF(obj) * return 0 # <<<<<<<<<<<<<< @@ -3321,7 +3700,7 @@ * buffcount = PySequence_Fast_GET_SIZE(bufflist) * buffers = PySequence_Fast_ITEMS(bufflist) */ - __pyx_t_1 = PySequence_Fast(__pyx_v_bufflist, __pyx_k_10); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PySequence_Fast(__pyx_v_bufflist, __pyx_k_14); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __Pyx_DECREF(__pyx_v_bufflist); __pyx_v_bufflist = __pyx_t_1; @@ -3452,7 +3831,7 @@ * if rc == SOCKET_ERROR: * rc = WSAGetLastError() # <<<<<<<<<<<<<< * if rc != ERROR_IO_PENDING: - * return rc, 0 + * PyMem_Free(ov) */ __pyx_v_rc = WSAGetLastError(); @@ -3460,8 +3839,8 @@ * if rc == SOCKET_ERROR: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< + * PyMem_Free(ov) * return rc, 0 - * */ __pyx_t_6 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_6) { @@ -3469,14 +3848,23 @@ /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":33 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) # <<<<<<<<<<<<<< + * return rc, 0 + * + */ + PyMem_Free(__pyx_v_ov); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":34 + * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) * return rc, 0 # <<<<<<<<<<<<<< * * Py_XINCREF(obj) */ __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7;} + __pyx_t_1 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7;} __Pyx_GOTREF(__pyx_t_1); - __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L7;} + __pyx_t_7 = PyTuple_New(2); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L7;} __Pyx_GOTREF(((PyObject *)__pyx_t_7)); PyTuple_SET_ITEM(__pyx_t_7, 0, __pyx_t_1); __Pyx_GIVEREF(__pyx_t_1); @@ -3494,7 +3882,7 @@ } __pyx_L12:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":35 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":36 * return rc, 0 * * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -3503,7 +3891,7 @@ */ Py_XINCREF(__pyx_v_obj); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":36 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":37 * * Py_XINCREF(obj) * return rc, bytes # <<<<<<<<<<<<<< @@ -3511,11 +3899,11 @@ * PyMem_Free(ws_buf) */ __Pyx_XDECREF(__pyx_r); - __pyx_t_7 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L7;} + __pyx_t_7 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_7)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L7;} __Pyx_GOTREF(__pyx_t_7); - __pyx_t_1 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L7;} + __pyx_t_1 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L7;} __Pyx_GOTREF(__pyx_t_1); - __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 36; __pyx_clineno = __LINE__; goto __pyx_L7;} + __pyx_t_8 = PyTuple_New(2); if (unlikely(!__pyx_t_8)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 37; __pyx_clineno = __LINE__; goto __pyx_L7;} __Pyx_GOTREF(((PyObject *)__pyx_t_8)); PyTuple_SET_ITEM(__pyx_t_8, 0, __pyx_t_7); __Pyx_GIVEREF(__pyx_t_7); @@ -3528,7 +3916,7 @@ goto __pyx_L6; } - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":38 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":39 * return rc, bytes * finally: * PyMem_Free(ws_buf) # <<<<<<<<<<<<<< @@ -3582,7 +3970,7 @@ return __pyx_r; } -/* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":40 +/* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":41 * PyMem_Free(ws_buf) * * def recvfrom(long s, object buff, object addr_buff, object addr_len_buff, object obj, unsigned long flags = 0): # <<<<<<<<<<<<<< @@ -3646,25 +4034,25 @@ values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__buff); if (likely(values[1])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, 1); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, 1); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } case 2: values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__addr_buff); if (likely(values[2])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, 2); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, 2); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } case 3: values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__addr_len_buff); if (likely(values[3])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, 3); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, 3); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } case 4: values[4] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__obj); if (likely(values[4])) kw_args--; else { - __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, 4); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, 4); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } case 5: if (kw_args > 0) { @@ -3673,7 +4061,7 @@ } } if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "recvfrom") < 0)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "recvfrom") < 0)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } } else { switch (PyTuple_GET_SIZE(__pyx_args)) { @@ -3687,36 +4075,36 @@ default: goto __pyx_L5_argtuple_error; } } - __pyx_v_s = __Pyx_PyInt_AsLong(values[0]); if (unlikely((__pyx_v_s == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_s = __Pyx_PyInt_AsLong(values[0]); if (unlikely((__pyx_v_s == (long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_v_buff = values[1]; __pyx_v_addr_buff = values[2]; __pyx_v_addr_len_buff = values[3]; __pyx_v_obj = values[4]; if (values[5]) { - __pyx_v_flags = __Pyx_PyInt_AsUnsignedLong(values[5]); if (unlikely((__pyx_v_flags == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_flags = __Pyx_PyInt_AsUnsignedLong(values[5]); if (unlikely((__pyx_v_flags == (unsigned long)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } else { __pyx_v_flags = ((unsigned long)0); } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("recvfrom", 0, 5, 6, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; __Pyx_AddTraceback("iocpsupport.recvfrom", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":49 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":50 * cdef Py_ssize_t size * * PyObject_AsWriteBuffer(buff, &ws_buf.buf, &size) # <<<<<<<<<<<<<< * ws_buf.len = size * PyObject_AsWriteBuffer(addr_buff, &c_addr_buff, &size) */ - __pyx_t_1 = PyObject_AsWriteBuffer(__pyx_v_buff, ((void **)(&__pyx_v_ws_buf.buf)), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 49; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyObject_AsWriteBuffer(__pyx_v_buff, ((void **)(&__pyx_v_ws_buf.buf)), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 50; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":50 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":51 * * PyObject_AsWriteBuffer(buff, &ws_buf.buf, &size) * ws_buf.len = size # <<<<<<<<<<<<<< @@ -3725,16 +4113,16 @@ */ __pyx_v_ws_buf.len = ((__pyx_t_11iocpsupport_DWORD)__pyx_v_size); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":51 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":52 * PyObject_AsWriteBuffer(buff, &ws_buf.buf, &size) * ws_buf.len = size * PyObject_AsWriteBuffer(addr_buff, &c_addr_buff, &size) # <<<<<<<<<<<<<< * c_addr_buff_len = size * PyObject_AsWriteBuffer(addr_len_buff, &c_addr_len_buff, &size) */ - __pyx_t_1 = PyObject_AsWriteBuffer(__pyx_v_addr_buff, ((void **)(&__pyx_v_c_addr_buff)), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 51; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyObject_AsWriteBuffer(__pyx_v_addr_buff, ((void **)(&__pyx_v_c_addr_buff)), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 52; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":52 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":53 * ws_buf.len = size * PyObject_AsWriteBuffer(addr_buff, &c_addr_buff, &size) * c_addr_buff_len = size # <<<<<<<<<<<<<< @@ -3743,16 +4131,16 @@ */ __pyx_v_c_addr_buff_len = ((int)__pyx_v_size); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":53 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":54 * PyObject_AsWriteBuffer(addr_buff, &c_addr_buff, &size) * c_addr_buff_len = size * PyObject_AsWriteBuffer(addr_len_buff, &c_addr_len_buff, &size) # <<<<<<<<<<<<<< * c_addr_len_buff_len = size * */ - __pyx_t_1 = PyObject_AsWriteBuffer(__pyx_v_addr_len_buff, ((void **)(&__pyx_v_c_addr_len_buff)), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 53; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyObject_AsWriteBuffer(__pyx_v_addr_len_buff, ((void **)(&__pyx_v_c_addr_len_buff)), (&__pyx_v_size)); if (unlikely(__pyx_t_1 == -1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 54; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":54 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":55 * c_addr_buff_len = size * PyObject_AsWriteBuffer(addr_len_buff, &c_addr_len_buff, &size) * c_addr_len_buff_len = size # <<<<<<<<<<<<<< @@ -3761,7 +4149,7 @@ */ __pyx_v_c_addr_len_buff_len = ((int)__pyx_v_size); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":56 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":57 * c_addr_len_buff_len = size * * if c_addr_len_buff_len != sizeof(int): # <<<<<<<<<<<<<< @@ -3771,20 +4159,20 @@ __pyx_t_2 = (__pyx_v_c_addr_len_buff_len != (sizeof(int))); if (__pyx_t_2) { - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":57 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":58 * * if c_addr_len_buff_len != sizeof(int): * raise ValueError, 'length of address length buffer needs to be sizeof(int)' # <<<<<<<<<<<<<< * * c_addr_len_buff[0] = c_addr_buff_len */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_11), 0, 0); - {__pyx_filename = __pyx_f[3]; __pyx_lineno = 57; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_15), 0, 0); + {__pyx_filename = __pyx_f[3]; __pyx_lineno = 58; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":59 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":60 * raise ValueError, 'length of address length buffer needs to be sizeof(int)' * * c_addr_len_buff[0] = c_addr_buff_len # <<<<<<<<<<<<<< @@ -3793,17 +4181,17 @@ */ (__pyx_v_c_addr_len_buff[0]) = __pyx_v_c_addr_buff_len; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":61 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":62 * c_addr_len_buff[0] = c_addr_buff_len * * ov = makeOV() # <<<<<<<<<<<<<< * if obj is not None: * ov.obj = obj */ - __pyx_t_3 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 61; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = __pyx_f_11iocpsupport_makeOV(); if (unlikely(__pyx_t_3 == NULL)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 62; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_v_ov = __pyx_t_3; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":62 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":63 * * ov = makeOV() * if obj is not None: # <<<<<<<<<<<<<< @@ -3813,7 +4201,7 @@ __pyx_t_2 = (__pyx_v_obj != Py_None); if (__pyx_t_2) { - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":63 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":64 * ov = makeOV() * if obj is not None: * ov.obj = obj # <<<<<<<<<<<<<< @@ -3825,7 +4213,7 @@ } __pyx_L7:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":65 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":66 * ov.obj = obj * * rc = WSARecvFrom(s, &ws_buf, 1, &bytes, &flags, c_addr_buff, c_addr_len_buff, ov, NULL) # <<<<<<<<<<<<<< @@ -3834,7 +4222,7 @@ */ __pyx_v_rc = WSARecvFrom(__pyx_v_s, (&__pyx_v_ws_buf), 1, (&__pyx_v_bytes), (&__pyx_v_flags), __pyx_v_c_addr_buff, __pyx_v_c_addr_len_buff, ((OVERLAPPED *)__pyx_v_ov), NULL); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":67 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":68 * rc = WSARecvFrom(s, &ws_buf, 1, &bytes, &flags, c_addr_buff, c_addr_len_buff, ov, NULL) * * if rc == SOCKET_ERROR: # <<<<<<<<<<<<<< @@ -3844,36 +4232,45 @@ __pyx_t_2 = (__pyx_v_rc == SOCKET_ERROR); if (__pyx_t_2) { - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":68 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":69 * * if rc == SOCKET_ERROR: * rc = WSAGetLastError() # <<<<<<<<<<<<<< * if rc != ERROR_IO_PENDING: - * return rc, 0 + * PyMem_Free(ov) */ __pyx_v_rc = WSAGetLastError(); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":69 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":70 * if rc == SOCKET_ERROR: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< + * PyMem_Free(ov) * return rc, 0 - * */ __pyx_t_2 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_2) { - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":70 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":71 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) # <<<<<<<<<<<<<< + * return rc, 0 + * + */ + PyMem_Free(__pyx_v_ov); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":72 + * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) * return rc, 0 # <<<<<<<<<<<<<< * * Py_XINCREF(obj) */ __Pyx_XDECREF(__pyx_r); - __pyx_t_4 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 72; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 70; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 72; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_5)); PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); @@ -3891,7 +4288,7 @@ } __pyx_L8:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":72 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":74 * return rc, 0 * * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -3900,18 +4297,18 @@ */ Py_XINCREF(__pyx_v_obj); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":73 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":75 * * Py_XINCREF(obj) * return rc, bytes # <<<<<<<<<<<<<< * */ __Pyx_XDECREF(__pyx_r); - __pyx_t_5 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 73; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 75; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_6)); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_5); __Pyx_GIVEREF(__pyx_t_5); @@ -4112,7 +4509,7 @@ * if rc == SOCKET_ERROR: * rc = WSAGetLastError() # <<<<<<<<<<<<<< * if rc != ERROR_IO_PENDING: - * return rc, bytes + * PyMem_Free(ov) */ __pyx_v_rc = WSAGetLastError(); @@ -4120,8 +4517,8 @@ * if rc == SOCKET_ERROR: * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: # <<<<<<<<<<<<<< + * PyMem_Free(ov) * return rc, bytes - * */ __pyx_t_3 = (__pyx_v_rc != ERROR_IO_PENDING); if (__pyx_t_3) { @@ -4129,16 +4526,25 @@ /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":24 * rc = WSAGetLastError() * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) # <<<<<<<<<<<<<< + * return rc, bytes + * + */ + PyMem_Free(__pyx_v_ov); + + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":25 + * if rc != ERROR_IO_PENDING: + * PyMem_Free(ov) * return rc, bytes # <<<<<<<<<<<<<< * * Py_XINCREF(obj) */ __Pyx_XDECREF(__pyx_r); - __pyx_t_4 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_4); - __pyx_t_5 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_5); - __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 24; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_6 = PyTuple_New(2); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 25; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_6)); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_4); __Pyx_GIVEREF(__pyx_t_4); @@ -4156,7 +4562,7 @@ } __pyx_L7:; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":26 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":27 * return rc, bytes * * Py_XINCREF(obj) # <<<<<<<<<<<<<< @@ -4165,7 +4571,7 @@ */ Py_XINCREF(__pyx_v_obj); - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":27 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":28 * * Py_XINCREF(obj) * return rc, bytes # <<<<<<<<<<<<<< @@ -4173,11 +4579,11 @@ * */ __Pyx_XDECREF(__pyx_r); - __pyx_t_6 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_6 = PyInt_FromLong(__pyx_v_rc); if (unlikely(!__pyx_t_6)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_6); - __pyx_t_5 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyLong_FromUnsignedLong(__pyx_v_bytes); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_5); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 27; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[4]; __pyx_lineno = 28; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_6); __Pyx_GIVEREF(__pyx_t_6); @@ -4395,18 +4801,22 @@ static __Pyx_StringTabEntry __pyx_string_tab[] = { {&__pyx_n_s_1, __pyx_k_1, sizeof(__pyx_k_1), 0, 0, 1, 1}, + {&__pyx_kp_s_10, __pyx_k_10, sizeof(__pyx_k_10), 0, 0, 1, 0}, {&__pyx_kp_s_11, __pyx_k_11, sizeof(__pyx_k_11), 0, 0, 1, 0}, {&__pyx_kp_s_12, __pyx_k_12, sizeof(__pyx_k_12), 0, 0, 1, 0}, + {&__pyx_kp_s_13, __pyx_k_13, sizeof(__pyx_k_13), 0, 0, 1, 0}, + {&__pyx_kp_s_15, __pyx_k_15, sizeof(__pyx_k_15), 0, 0, 1, 0}, + {&__pyx_kp_s_16, __pyx_k_16, sizeof(__pyx_k_16), 0, 0, 1, 0}, {&__pyx_n_s_2, __pyx_k_2, sizeof(__pyx_k_2), 0, 0, 1, 1}, {&__pyx_kp_s_3, __pyx_k_3, sizeof(__pyx_k_3), 0, 0, 1, 0}, {&__pyx_kp_s_5, __pyx_k_5, sizeof(__pyx_k_5), 0, 0, 1, 0}, {&__pyx_kp_s_6, __pyx_k_6, sizeof(__pyx_k_6), 0, 0, 1, 0}, {&__pyx_kp_s_7, __pyx_k_7, sizeof(__pyx_k_7), 0, 0, 1, 0}, {&__pyx_kp_s_8, __pyx_k_8, sizeof(__pyx_k_8), 0, 0, 1, 0}, - {&__pyx_kp_s_9, __pyx_k_9, sizeof(__pyx_k_9), 0, 0, 1, 0}, {&__pyx_n_s__AllocateReadBuffer, __pyx_k__AllocateReadBuffer, sizeof(__pyx_k__AllocateReadBuffer), 0, 0, 1, 1}, {&__pyx_n_s__Event, __pyx_k__Event, sizeof(__pyx_k__Event), 0, 0, 1, 1}, {&__pyx_n_s__MemoryError, __pyx_k__MemoryError, sizeof(__pyx_k__MemoryError), 0, 0, 1, 1}, + {&__pyx_n_s__RuntimeError, __pyx_k__RuntimeError, sizeof(__pyx_k__RuntimeError), 0, 0, 1, 1}, {&__pyx_n_s__ValueError, __pyx_k__ValueError, sizeof(__pyx_k__ValueError), 0, 0, 1, 1}, {&__pyx_n_s__WSAAddressToString, __pyx_k__WSAAddressToString, sizeof(__pyx_k__WSAAddressToString), 0, 0, 1, 1}, {&__pyx_n_s__WindowsError, __pyx_k__WindowsError, sizeof(__pyx_k__WindowsError), 0, 0, 1, 1}, @@ -4442,11 +4852,13 @@ {&__pyx_n_s__self, __pyx_k__self, sizeof(__pyx_k__self), 0, 0, 1, 1}, {&__pyx_n_s__send, __pyx_k__send, sizeof(__pyx_k__send), 0, 0, 1, 1}, {&__pyx_n_s__socket, __pyx_k__socket, sizeof(__pyx_k__socket), 0, 0, 1, 1}, + {&__pyx_n_s__split, __pyx_k__split, sizeof(__pyx_k__split), 0, 0, 1, 1}, {0, 0, 0, 0, 0, 0, 0} }; static int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_ValueError = __Pyx_GetName(__pyx_b, __pyx_n_s__ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __pyx_builtin_MemoryError = __Pyx_GetName(__pyx_b, __pyx_n_s__MemoryError); if (!__pyx_builtin_MemoryError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 123; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_builtin_ValueError = __Pyx_GetName(__pyx_b, __pyx_n_s__ValueError); if (!__pyx_builtin_ValueError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 304; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_builtin_MemoryError = __Pyx_GetName(__pyx_b, __pyx_n_s__MemoryError); if (!__pyx_builtin_MemoryError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_builtin_RuntimeError = __Pyx_GetName(__pyx_b, __pyx_n_s__RuntimeError); if (!__pyx_builtin_RuntimeError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 272; __pyx_clineno = __LINE__; goto __pyx_L1_error;} return 0; __pyx_L1_error:; return -1; @@ -4456,14 +4868,14 @@ __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants"); - /* "iocpsupport.pyx":221 + /* "iocpsupport.pyx":233 * raise_error(0, 'WSAAddressToString') * host, sa_port = PyString_FromString(buff), ntohs(sin6.sin6_port) * host, port = host.rsplit(':', 1) # <<<<<<<<<<<<<< * port = int(port) * assert host[0] == '[' */ - __pyx_k_tuple_4 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 221; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_k_tuple_4 = PyTuple_New(2); if (unlikely(!__pyx_k_tuple_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 233; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_k_tuple_4)); __Pyx_INCREF(((PyObject *)__pyx_kp_s_3)); PyTuple_SET_ITEM(__pyx_k_tuple_4, 0, ((PyObject *)__pyx_kp_s_3)); @@ -4472,6 +4884,20 @@ PyTuple_SET_ITEM(__pyx_k_tuple_4, 1, __pyx_int_1); __Pyx_GIVEREF(__pyx_int_1); __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_4)); + + /* "iocpsupport.pyx":264 + * cdef int addrlen = sizeof(sockaddr_in6) + * host, port, flow, scope = addr + * host = host.split("%")[0] # remove scope ID, if any # <<<<<<<<<<<<<< + * + * hoststr = PyString_AsString(host) + */ + __pyx_k_tuple_9 = PyTuple_New(1); if (unlikely(!__pyx_k_tuple_9)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 264; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_k_tuple_9)); + __Pyx_INCREF(((PyObject *)__pyx_kp_s_8)); + PyTuple_SET_ITEM(__pyx_k_tuple_9, 0, ((PyObject *)__pyx_kp_s_8)); + __Pyx_GIVEREF(((PyObject *)__pyx_kp_s_8)); + __Pyx_GIVEREF(((PyObject *)__pyx_k_tuple_9)); __Pyx_RefNannyFinishContext(); return 0; __pyx_L1_error:; @@ -4549,98 +4975,98 @@ /*--- Variable export code ---*/ /*--- Function export code ---*/ /*--- Type init code ---*/ - if (PyType_Ready(&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__Pyx_SetAttrString(__pyx_m, "CompletionPort", (PyObject *)&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 139; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyType_Ready(&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 148; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (__Pyx_SetAttrString(__pyx_m, "CompletionPort", (PyObject *)&__pyx_type_11iocpsupport_CompletionPort) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 148; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_ptype_11iocpsupport_CompletionPort = &__pyx_type_11iocpsupport_CompletionPort; /*--- Type import code ---*/ /*--- Variable import code ---*/ /*--- Function import code ---*/ /*--- Execution code ---*/ - /* "iocpsupport.pyx":132 + /* "iocpsupport.pyx":141 * raise WindowsError(message, err) * * class Event: # <<<<<<<<<<<<<< * def __init__(self, callback, owner, **kw): * self.callback = callback */ - __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_1)); - /* "iocpsupport.pyx":133 + /* "iocpsupport.pyx":142 * * class Event: * def __init__(self, callback, owner, **kw): # <<<<<<<<<<<<<< * self.callback = callback * self.owner = owner */ - __pyx_t_2 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_11iocpsupport_5Event___init__, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __pyx_binding_PyCFunctionType_NewEx(&__pyx_mdef_11iocpsupport_5Event___init__, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - if (PyObject_SetItem(__pyx_t_1, __pyx_n_s____init__, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 133; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetItem(__pyx_t_1, __pyx_n_s____init__, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 142; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; - /* "iocpsupport.pyx":132 + /* "iocpsupport.pyx":141 * raise WindowsError(message, err) * * class Event: # <<<<<<<<<<<<<< * def __init__(self, callback, owner, **kw): * self.callback = callback */ - __pyx_t_2 = __Pyx_CreateClass(((PyObject *)__pyx_empty_tuple), ((PyObject *)__pyx_t_1), __pyx_n_s__Event, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = __Pyx_CreateClass(((PyObject *)__pyx_empty_tuple), ((PyObject *)__pyx_t_1), __pyx_n_s__Event, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Event, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 132; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__Event, __pyx_t_2) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0; __Pyx_DECREF(((PyObject *)__pyx_t_1)); __pyx_t_1 = 0; - /* "iocpsupport.pyx":196 + /* "iocpsupport.pyx":208 * CloseHandle(self.port) * * def makesockaddr(object buff): # <<<<<<<<<<<<<< * cdef void *mem_buffer * cdef Py_ssize_t size */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_makesockaddr, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 196; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_makesockaddr, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 208; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__makesockaddr, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 196; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__makesockaddr, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 208; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":244 - * dest.sin_port = htons(port) + /* "iocpsupport.pyx":279 + * * * def AllocateReadBuffer(int size): # <<<<<<<<<<<<<< * return PyBuffer_New(size) * */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_1AllocateReadBuffer, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_1AllocateReadBuffer, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 279; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__AllocateReadBuffer, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 244; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__AllocateReadBuffer, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 279; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":247 + /* "iocpsupport.pyx":282 * return PyBuffer_New(size) * * def maxAddrLen(long s): # <<<<<<<<<<<<<< * cdef WSAPROTOCOL_INFO wsa_pi * cdef int size, rc */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_2maxAddrLen, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_2maxAddrLen, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 282; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__maxAddrLen, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 247; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__maxAddrLen, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 282; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":267 + /* "iocpsupport.pyx":302 * return wsa_pi.iAddressFamily * * import socket # for WSAStartup # <<<<<<<<<<<<<< * if not initWinsockPointers(): * raise ValueError, 'Failed to initialize Winsock function vectors' */ - __pyx_t_1 = __Pyx_Import(((PyObject *)__pyx_n_s__socket), 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 267; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_Import(((PyObject *)__pyx_n_s__socket), 0, -1); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 302; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__socket, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 267; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__socket, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 302; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "iocpsupport.pyx":268 + /* "iocpsupport.pyx":303 * * import socket # for WSAStartup * if not initWinsockPointers(): # <<<<<<<<<<<<<< @@ -4650,29 +5076,29 @@ __pyx_t_3 = (!initWinsockPointers()); if (__pyx_t_3) { - /* "iocpsupport.pyx":269 + /* "iocpsupport.pyx":304 * import socket # for WSAStartup * if not initWinsockPointers(): * raise ValueError, 'Failed to initialize Winsock function vectors' # <<<<<<<<<<<<<< * * have_connectex = (lpConnectEx != NULL) */ - __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_12), 0, 0); - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 269; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_Raise(__pyx_builtin_ValueError, ((PyObject *)__pyx_kp_s_16), 0, 0); + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 304; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L2; } __pyx_L2:; - /* "iocpsupport.pyx":271 + /* "iocpsupport.pyx":306 * raise ValueError, 'Failed to initialize Winsock function vectors' * * have_connectex = (lpConnectEx != NULL) # <<<<<<<<<<<<<< * * include 'acceptex.pxi' */ - __pyx_t_1 = __Pyx_PyBool_FromLong((lpConnectEx != NULL)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = __Pyx_PyBool_FromLong((lpConnectEx != NULL)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 306; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__have_connectex, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__have_connectex, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 306; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":5 @@ -4687,16 +5113,16 @@ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__accept, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":33 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\acceptex.pxi":34 * return 0 * * def get_accept_addrs(long s, object buff): # <<<<<<<<<<<<<< * cdef WSAPROTOCOL_INFO wsa_pi * cdef int locallen, remotelen */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_4get_accept_addrs, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_4get_accept_addrs, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__get_accept_addrs, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 33; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__get_accept_addrs, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[1]; __pyx_lineno = 34; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\connectex.pxi":5 @@ -4715,16 +5141,16 @@ if (PyObject_SetAttr(__pyx_m, __pyx_n_s__recv, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 5; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":40 + /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsarecv.pxi":41 * PyMem_Free(ws_buf) * * def recvfrom(long s, object buff, object addr_buff, object addr_len_buff, object obj, unsigned long flags = 0): # <<<<<<<<<<<<<< * cdef int rc, c_addr_buff_len, c_addr_len_buff_len * cdef myOVERLAPPED *ov */ - __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_7recvfrom, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_11iocpsupport_7recvfrom, NULL, __pyx_n_s__iocpsupport); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__recvfrom, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 40; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__recvfrom, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[3]; __pyx_lineno = 41; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* "C:\t\twisted\twisted\internet\iocpreactor\iocpsupport\wsasend.pxi":5 diff -Nru twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx --- twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx 2011-11-25 21:21:10.000000000 +0000 +++ twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/iocpsupport.pyx 2012-03-27 12:27:04.000000000 +0000 @@ -63,15 +63,21 @@ cdef extern from '': struct sockaddr: - int sa_family + unsigned short int sa_family char sa_data[0] cdef struct in_addr: unsigned long s_addr struct sockaddr_in: int sin_port in_addr sin_addr + cdef struct in6_addr: + char s6_addr[16] struct sockaddr_in6: - int sin6_port + short int sin6_family + unsigned short int sin6_port + unsigned long int sin6_flowinfo + in6_addr sin6_addr + unsigned long int sin6_scope_id int getsockopt(SOCKET s, int level, int optname, char *optval, int *optlen) enum: SOL_SOCKET @@ -101,6 +107,9 @@ WSAPROTOCOL_INFO *lpProtocolInfo, char *lpszAddressString, DWORD *lpdwAddressStringLength) + int WSAStringToAddressA(char *AddressString, int AddressFamily, + WSAPROTOCOL_INFO *lpProtocolInfo, + sockaddr *lpAddress, int *lpAddressLength) cdef extern from 'string.h': void *memset(void *s, int c, size_t n) @@ -188,6 +197,9 @@ rc = PostQueuedCompletionStatus(self.port, bytes, key, ov) if not rc: + if ov: + Py_DECREF(obj) + PyMem_Free(ov) raise_error(0, 'PostQueuedCompletionStatus') def __del__(self): @@ -227,6 +239,7 @@ else: return PyString_FromStringAndSize(addr.sa_data, sizeof(addr.sa_data)) + cdef object fillinetaddr(sockaddr_in *dest, object addr): cdef unsigned short port cdef unsigned long res @@ -241,6 +254,28 @@ dest.sin_port = htons(port) + +cdef object fillinet6addr(sockaddr_in6 *dest, object addr): + cdef unsigned short port + cdef unsigned long res + cdef char *hoststr + cdef int addrlen = sizeof(sockaddr_in6) + host, port, flow, scope = addr + host = host.split("%")[0] # remove scope ID, if any + + hoststr = PyString_AsString(host) + cdef int parseresult = WSAStringToAddressA(hoststr, AF_INET6, NULL, + dest, &addrlen) + if parseresult == SOCKET_ERROR: + raise ValueError, 'invalid IPv6 address %r' % (host,) + if parseresult != 0: + raise RuntimeError, 'undefined error occurred during address parsing' + # sin6_host field was handled by WSAStringToAddress + dest.sin6_port = htons(port) + dest.sin6_flowinfo = flow + dest.sin6_scope_id = scope + + def AllocateReadBuffer(int size): return PyBuffer_New(size) diff -Nru twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/wsarecv.pxi twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/wsarecv.pxi --- twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/wsarecv.pxi 2011-11-25 21:21:10.000000000 +0000 +++ twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/wsarecv.pxi 2012-03-12 23:15:18.000000000 +0000 @@ -30,6 +30,7 @@ if rc == SOCKET_ERROR: rc = WSAGetLastError() if rc != ERROR_IO_PENDING: + PyMem_Free(ov) return rc, 0 Py_XINCREF(obj) @@ -67,6 +68,7 @@ if rc == SOCKET_ERROR: rc = WSAGetLastError() if rc != ERROR_IO_PENDING: + PyMem_Free(ov) return rc, 0 Py_XINCREF(obj) diff -Nru twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/wsasend.pxi twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/wsasend.pxi --- twisted-12.0.0/twisted/internet/iocpreactor/iocpsupport/wsasend.pxi 2011-11-25 21:21:10.000000000 +0000 +++ twisted-12.2.0/twisted/internet/iocpreactor/iocpsupport/wsasend.pxi 2012-03-12 23:15:18.000000000 +0000 @@ -21,6 +21,7 @@ if rc == SOCKET_ERROR: rc = WSAGetLastError() if rc != ERROR_IO_PENDING: + PyMem_Free(ov) return rc, bytes Py_XINCREF(obj) diff -Nru twisted-12.0.0/twisted/internet/iocpreactor/tcp.py twisted-12.2.0/twisted/internet/iocpreactor/tcp.py --- twisted-12.0.0/twisted/internet/iocpreactor/tcp.py 2011-12-11 03:20:29.000000000 +0000 +++ twisted-12.2.0/twisted/internet/iocpreactor/tcp.py 2012-03-27 12:27:04.000000000 +0000 @@ -12,7 +12,7 @@ from twisted.internet import interfaces, error, address, main, defer from twisted.internet.abstract import _LogOwner, isIPAddress, isIPv6Address from twisted.internet.tcp import _SocketCloser, Connector as TCPConnector -from twisted.internet.tcp import _AbortingMixin +from twisted.internet.tcp import _AbortingMixin, _BaseBaseClient, _BaseTCPClient from twisted.python import log, failure, reflect, util from twisted.internet.iocpreactor import iocpsupport as _iocp, abstract @@ -227,7 +227,7 @@ -class Client(Connection): +class Client(_BaseBaseClient, _BaseTCPClient, Connection): """ @ivar _tlsClientDefault: Always C{True}, indicating that this is a client connection, and by default when TLS is negotiated this class will act as @@ -237,67 +237,43 @@ socketType = socket.SOCK_STREAM _tlsClientDefault = True + _commonConnection = Connection def __init__(self, host, port, bindAddress, connector, reactor): - self.connector = connector - self.addr = (host, port) - self.reactor = reactor # ConnectEx documentation says socket _has_ to be bound if bindAddress is None: bindAddress = ('', 0) - - try: - try: - skt = reactor.createSocket(self.addressFamily, self.socketType) - except socket.error, se: - raise error.ConnectBindError(se[0], se[1]) - else: - try: - skt.bind(bindAddress) - except socket.error, se: - raise error.ConnectBindError(se[0], se[1]) - self.socket = skt - Connection.__init__(self, skt, None, reactor) - reactor.callLater(0, self.resolveAddress) - except error.ConnectBindError, err: - reactor.callLater(0, self.failIfNotConnected, err) + self.reactor = reactor # createInternetSocket needs this + _BaseTCPClient.__init__(self, host, port, bindAddress, connector, + reactor) - def resolveAddress(self): - if isIPAddress(self.addr[0]): - self._setRealAddress(self.addr[0]) - else: - d = self.reactor.resolve(self.addr[0]) - d.addCallbacks(self._setRealAddress, self.failIfNotConnected) - - - def _setRealAddress(self, address): - self.realAddress = (address, self.addr[1]) - self.doConnect() + def createInternetSocket(self): + """ + Create a socket registered with the IOCP reactor. + @see: L{_BaseTCPClient} + """ + return self.reactor.createSocket(self.addressFamily, self.socketType) - def failIfNotConnected(self, err): - if (self.connected or self.disconnected or - not hasattr(self, "connector")): - return - try: - self._closeSocket(True) - except AttributeError: - pass - else: - del self.socket, self.getFileHandle - self.reactor.removeActiveHandle(self) + def _collectSocketDetails(self): + """ + Clean up potentially circular references to the socket and to its + C{getFileHandle} method. - self.connector.connectionFailed(failure.Failure(err)) - del self.connector + @see: L{_BaseBaseClient} + """ + del self.socket, self.getFileHandle - def stopConnecting(self): + def _stopReadingAndWriting(self): """ - Stop attempt to connect. + Remove the active handle from the reactor. + + @see: L{_BaseBaseClient} """ - self.failIfNotConnected(error.UserError()) + self.reactor.removeActiveHandle(self) def cbConnect(self, rc, bytes, evt): @@ -328,39 +304,7 @@ rc = _iocp.connect(self.socket.fileno(), self.realAddress, evt) if rc and rc != ERROR_IO_PENDING: - self.cbConnect(rc, 0, 0, evt) - - - def getHost(self): - """ - Returns an IPv4Address. - - This indicates the address from which I am connecting. - """ - return address.IPv4Address('TCP', *self.socket.getsockname()) - - - def getPeer(self): - """ - Returns an IPv4Address. - - This indicates the address that I am connected to. - """ - return address.IPv4Address('TCP', *self.realAddress) - - - def __repr__(self): - s = ('<%s to %s at %x>' % - (self.__class__, self.addr, util.unsignedID(self))) - return s - - - def connectionLost(self, reason): - if not self.connected: - self.failIfNotConnected(error.ConnectError(string=reason)) - else: - Connection.connectionLost(self, reason) - self.connector.connectionLost(reason) + self.cbConnect(rc, 0, evt) diff -Nru twisted-12.0.0/twisted/internet/kqreactor.py twisted-12.2.0/twisted/internet/kqreactor.py --- twisted-12.0.0/twisted/internet/kqreactor.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/internet/kqreactor.py 2012-01-23 22:55:41.000000000 +0000 @@ -4,68 +4,32 @@ """ A kqueue()/kevent() based implementation of the Twisted main loop. -To install the event loop (and you should do this before any connections, -listeners or connectors are added):: +To use this reactor, start your application specifying the kqueue reactor:: - | from twisted.internet import kqreactor - | kqreactor.install() + twistd --reactor kqueue ... -This reactor only works on FreeBSD and requires PyKQueue 1.3, which is -available at: U{http://people.freebsd.org/~dwhite/PyKQueue/} +To install the event loop from code (and you should do this before any +connections, listeners or connectors are added):: + from twisted.internet import kqreactor + kqreactor.install() +This implementation depends on Python 2.6 or higher which has kqueue support +built in the select module. -You're going to need to patch PyKqueue:: - - ===================================================== - --- PyKQueue-1.3/kqsyscallmodule.c Sun Jan 28 21:59:50 2001 - +++ PyKQueue-1.3/kqsyscallmodule.c.new Tue Jul 30 18:06:08 2002 - @@ -137,7 +137,7 @@ - } - - statichere PyTypeObject KQEvent_Type = { - - PyObject_HEAD_INIT(NULL) - + PyObject_HEAD_INIT(&PyType_Type) - 0, // ob_size - "KQEvent", // tp_name - sizeof(KQEventObject), // tp_basicsize - @@ -291,13 +291,14 @@ - - /* Build timespec for timeout */ - totimespec.tv_sec = timeout / 1000; - - totimespec.tv_nsec = (timeout % 1000) * 100000; - + totimespec.tv_nsec = (timeout % 1000) * 1000000; - - // printf("timespec: sec=%d nsec=%d\\n", totimespec.tv_sec, totimespec.tv_nsec); - - /* Make the call */ - - - + Py_BEGIN_ALLOW_THREADS - gotNumEvents = kevent (self->fd, changelist, haveNumEvents, triggered, wantNumEvents, &totimespec); - + Py_END_ALLOW_THREADS - - /* Don't need the input event list anymore, so get rid of it */ - free (changelist); - @@ -361,7 +362,7 @@ - statichere PyTypeObject KQueue_Type = { - /* The ob_type field must be initialized in the module init function - * to be portable to Windows without using C++. */ - - PyObject_HEAD_INIT(NULL) - + PyObject_HEAD_INIT(&PyType_Type) - 0, /*ob_size*/ - "KQueue", /*tp_name*/ - sizeof(KQueueObject), /*tp_basicsize*/ - +Note, that you should use Python 2.6.5 or higher, since previous implementations +of select.kqueue had U{http://bugs.python.org/issue5910} not yet fixed. """ -import errno, sys +import errno from zope.interface import implements -from kqsyscall import EVFILT_READ, EVFILT_WRITE, EV_DELETE, EV_ADD -from kqsyscall import kqueue, kevent +from select import kqueue, kevent +from select import KQ_FILTER_READ, KQ_FILTER_WRITE +from select import KQ_EV_DELETE, KQ_EV_ADD, KQ_EV_EOF -from twisted.internet.interfaces import IReactorFDSet +from twisted.internet.interfaces import IReactorFDSet, IReactorDaemonize from twisted.python import log, failure from twisted.internet import main, posixbase @@ -73,7 +37,8 @@ class KQueueReactor(posixbase.PosixReactorBase): """ - A reactor that uses kqueue(2)/kevent(2). + A reactor that uses kqueue(2)/kevent(2) and relies on Python 2.6 or higher + which has built in support for kqueue in the select module. @ivar _kq: A L{kqueue} which will be used to check for I/O readiness. @@ -95,12 +60,18 @@ dispatched to the corresponding L{FileDescriptor} instances in C{_selectables}. """ - implements(IReactorFDSet) + implements(IReactorFDSet, IReactorDaemonize) + def __init__(self): """ Initialize kqueue object, file descriptor tracking dictionaries, and the base class. + + See: + - http://docs.python.org/library/select.html + - www.freebsd.org/cgi/man.cgi?query=kqueue + - people.freebsd.org/~jlemon/papers/kqueue.pdf """ self._kq = kqueue() self._reads = {} @@ -109,50 +80,134 @@ posixbase.PosixReactorBase.__init__(self) - def _updateRegistration(self, *args): - self._kq.kevent([kevent(*args)], 0, 0) + def _updateRegistration(self, fd, filter, op): + """ + Private method for changing kqueue registration on a given FD + filtering for events given filter/op. This will never block and + returns nothing. + """ + self._kq.control([kevent(fd, filter, op)], 0, 0) + + + def beforeDaemonize(self): + """ + Implement L{IReactorDaemonize.beforeDaemonize}. + """ + # Twisted-internal method called during daemonization (when application + # is started via twistd). This is called right before the magic double + # forking done for daemonization. We cleanly close the kqueue() and later + # recreate it. This is needed since a) kqueue() are not inherited across + # forks and b) twistd will create the reactor already before daemonization + # (and will also add at least 1 reader to the reactor, an instance of + # twisted.internet.posixbase._UnixWaker). + # + # See: twisted.scripts._twistd_unix.daemonize() + self._kq.close() + self._kq = None + + + def afterDaemonize(self): + """ + Implement L{IReactorDaemonize.afterDaemonize}. + """ + # Twisted-internal method called during daemonization. This is called right + # after daemonization and recreates the kqueue() and any readers/writers + # that were added before. Note that you MUST NOT call any reactor methods + # in between beforeDaemonize() and afterDaemonize()! + self._kq = kqueue() + for fd in self._reads: + self._updateRegistration(fd, KQ_FILTER_READ, KQ_EV_ADD) + for fd in self._writes: + self._updateRegistration(fd, KQ_FILTER_WRITE, KQ_EV_ADD) + def addReader(self, reader): - """Add a FileDescriptor for notification of data available to read. + """ + Implement L{IReactorFDSet.addReader}. """ fd = reader.fileno() if fd not in self._reads: - self._selectables[fd] = reader - self._reads[fd] = 1 - self._updateRegistration(fd, EVFILT_READ, EV_ADD) + try: + self._updateRegistration(fd, KQ_FILTER_READ, KQ_EV_ADD) + except OSError: + pass + finally: + self._selectables[fd] = reader + self._reads[fd] = 1 + def addWriter(self, writer): - """Add a FileDescriptor for notification of data available to write. + """ + Implement L{IReactorFDSet.addWriter}. """ fd = writer.fileno() if fd not in self._writes: - self._selectables[fd] = writer - self._writes[fd] = 1 - self._updateRegistration(fd, EVFILT_WRITE, EV_ADD) + try: + self._updateRegistration(fd, KQ_FILTER_WRITE, KQ_EV_ADD) + except OSError: + pass + finally: + self._selectables[fd] = writer + self._writes[fd] = 1 + def removeReader(self, reader): - """Remove a Selectable for notification of data available to read. """ - fd = reader.fileno() + Implement L{IReactorFDSet.removeReader}. + """ + wasLost = False + try: + fd = reader.fileno() + except: + fd = -1 + if fd == -1: + for fd, fdes in self._selectables.items(): + if reader is fdes: + wasLost = True + break + else: + return if fd in self._reads: del self._reads[fd] if fd not in self._writes: del self._selectables[fd] - self._updateRegistration(fd, EVFILT_READ, EV_DELETE) + if not wasLost: + try: + self._updateRegistration(fd, KQ_FILTER_READ, KQ_EV_DELETE) + except OSError: + pass + def removeWriter(self, writer): - """Remove a Selectable for notification of data available to write. """ - fd = writer.fileno() + Implement L{IReactorFDSet.removeWriter}. + """ + wasLost = False + try: + fd = writer.fileno() + except: + fd = -1 + if fd == -1: + for fd, fdes in self._selectables.items(): + if writer is fdes: + wasLost = True + break + else: + return if fd in self._writes: del self._writes[fd] if fd not in self._reads: del self._selectables[fd] - self._updateRegistration(fd, EVFILT_WRITE, EV_DELETE) + if not wasLost: + try: + self._updateRegistration(fd, KQ_FILTER_WRITE, KQ_EV_DELETE) + except OSError: + pass + def removeAll(self): """ - Remove all selectables, and return a list of them. + Implement L{IReactorFDSet.removeAll}. """ return self._removeAll( [self._selectables[fd] for fd in self._reads], @@ -160,62 +215,91 @@ def getReaders(self): + """ + Implement L{IReactorFDSet.getReaders}. + """ return [self._selectables[fd] for fd in self._reads] def getWriters(self): + """ + Implement L{IReactorFDSet.getWriters}. + """ return [self._selectables[fd] for fd in self._writes] def doKEvent(self, timeout): - """Poll the kqueue for new events.""" + """ + Poll the kqueue for new events. + """ if timeout is None: - timeout = 1000 - else: - timeout = int(timeout * 1000) # convert seconds to milliseconds + timeout = 1 try: - l = self._kq.kevent([], len(self._selectables), timeout) + l = self._kq.control([], len(self._selectables), timeout) except OSError, e: if e[0] == errno.EINTR: return else: raise + _drdw = self._doWriteOrRead for event in l: - why = None - fd, filter = event.ident, event.filter + fd = event.ident try: selectable = self._selectables[fd] except KeyError: # Handles the infrequent case where one selectable's # handler disconnects another. continue - log.callWithLogger(selectable, _drdw, selectable, fd, filter) + else: + log.callWithLogger(selectable, _drdw, selectable, fd, event) - def _doWriteOrRead(self, selectable, fd, filter): - try: - if filter == EVFILT_READ: - why = selectable.doRead() - if filter == EVFILT_WRITE: - why = selectable.doWrite() - if not selectable.fileno() == fd: - why = main.CONNECTION_LOST - except: - why = sys.exc_info()[1] - log.deferr() + + def _doWriteOrRead(self, selectable, fd, event): + """ + Private method called when a FD is ready for reading, writing or was + lost. Do the work and raise errors where necessary. + """ + why = None + inRead = False + (filter, flags, data, fflags) = ( + event.filter, event.flags, event.data, event.fflags) + + if flags & KQ_EV_EOF and data and fflags: + why = main.CONNECTION_LOST + else: + try: + if selectable.fileno() == -1: + inRead = False + why = posixbase._NO_FILEDESC + else: + if filter == KQ_FILTER_READ: + inRead = True + why = selectable.doRead() + if filter == KQ_FILTER_WRITE: + inRead = False + why = selectable.doWrite() + except: + # Any exception from application code gets logged and will + # cause us to disconnect the selectable. + why = failure.Failure() + log.err(why, "An exception was raised from application code" \ + " while processing a reactor selectable") if why: - self.removeReader(selectable) - self.removeWriter(selectable) - selectable.connectionLost(failure.Failure(why)) + self._disconnectSelectable(selectable, why, inRead) doIteration = doKEvent def install(): - k = KQueueReactor() - main.installReactor(k) + """ + Install the kqueue() reactor. + """ + p = KQueueReactor() + from twisted.internet.main import installReactor + installReactor(p) __all__ = ["KQueueReactor", "install"] diff -Nru twisted-12.0.0/twisted/internet/posixbase.py twisted-12.2.0/twisted/internet/posixbase.py --- twisted-12.0.0/twisted/internet/posixbase.py 2011-12-08 03:37:41.000000000 +0000 +++ twisted-12.2.0/twisted/internet/posixbase.py 2012-07-28 14:29:16.000000000 +0000 @@ -16,7 +16,8 @@ from twisted.python.compat import set from twisted.internet.interfaces import IReactorUNIX, IReactorUNIXDatagram -from twisted.internet.interfaces import IReactorTCP, IReactorUDP, IReactorSSL, _IReactorArbitrary +from twisted.internet.interfaces import ( + IReactorTCP, IReactorUDP, IReactorSSL, _IReactorArbitrary, IReactorSocket) from twisted.internet.interfaces import IReactorProcess, IReactorMulticast from twisted.internet.interfaces import IHalfCloseableDescriptor from twisted.internet import error @@ -233,14 +234,11 @@ -class PosixReactorBase(_SignalReactorMixin, ReactorBase): - """ - A basis for reactors that use file descriptors. - @ivar _childWaker: C{None} or a reference to the L{_SIGCHLDWaker} - which is used to properly notice child process termination. +class _DisconnectSelectableMixin(object): + """ + Mixin providing the C{_disconnectSelectable} method. """ - implements(_IReactorArbitrary, IReactorTCP, IReactorUDP, IReactorMulticast) def _disconnectSelectable(self, selectable, why, isRead, faildict={ error.ConnectionDone: failure.Failure(error.ConnectionDone()), @@ -266,6 +264,17 @@ selectable.connectionLost(failure.Failure(why)) + +class PosixReactorBase(_SignalReactorMixin, _DisconnectSelectableMixin, + ReactorBase): + """ + A basis for reactors that use file descriptors. + + @ivar _childWaker: C{None} or a reference to the L{_SIGCHLDWaker} + which is used to properly notice child process termination. + """ + implements(_IReactorArbitrary, IReactorTCP, IReactorUDP, IReactorMulticast) + # Callable that creates a waker, overrideable so that subclasses can # substitute their own implementation: _wakerFactory = _Waker @@ -427,6 +436,37 @@ return p + # IReactorSocket (but not on Windows) + + def adoptStreamPort(self, fileDescriptor, addressFamily, factory): + """ + Create a new L{IListeningPort} from an already-initialized socket. + + This just dispatches to a suitable port implementation (eg from + L{IReactorTCP}, etc) based on the specified C{addressFamily}. + + @see: L{twisted.internet.interfaces.IReactorSocket.adoptStreamPort} + """ + if addressFamily not in (socket.AF_INET, socket.AF_INET6): + raise error.UnsupportedAddressFamily(addressFamily) + + p = tcp.Port._fromListeningDescriptor( + self, fileDescriptor, addressFamily, factory) + p.startListening() + return p + + def adoptStreamConnection(self, fileDescriptor, addressFamily, factory): + """ + @see: + L{twisted.internet.interfaces.IReactorSocket.adoptStreamConnection} + """ + if addressFamily not in (socket.AF_INET, socket.AF_INET6): + raise error.UnsupportedAddressFamily(addressFamily) + + return tcp.Server._fromConnectedSocket( + fileDescriptor, addressFamily, factory, self) + + # IReactorTCP def listenTCP(self, port, factory, backlog=50, interface=''): @@ -606,5 +646,7 @@ classImplements(PosixReactorBase, IReactorUNIX, IReactorUNIXDatagram) if processEnabled: classImplements(PosixReactorBase, IReactorProcess) +if getattr(socket, 'fromfd', None) is not None: + classImplements(PosixReactorBase, IReactorSocket) __all__ = ["PosixReactorBase"] diff -Nru twisted-12.0.0/twisted/internet/process.py twisted-12.2.0/twisted/internet/process.py --- twisted-12.0.0/twisted/internet/process.py 2011-08-09 00:02:08.000000000 +0000 +++ twisted-12.2.0/twisted/internet/process.py 2012-07-08 18:39:59.000000000 +0000 @@ -337,7 +337,13 @@ signalID = getattr(signal, 'SIG%s' % (signalID,)) if self.pid is None: raise ProcessExitedAlready() - os.kill(self.pid, signalID) + try: + os.kill(self.pid, signalID) + except OSError, e: + if e.errno == errno.ESRCH: + raise ProcessExitedAlready() + else: + raise def _resetSignalDisposition(self): diff -Nru twisted-12.0.0/twisted/internet/protocol.py twisted-12.2.0/twisted/internet/protocol.py --- twisted-12.0.0/twisted/internet/protocol.py 2011-10-22 03:14:14.000000000 +0000 +++ twisted-12.2.0/twisted/internet/protocol.py 2012-05-12 13:55:41.000000000 +0000 @@ -623,7 +623,8 @@ def processEnded(self, reason): """ - This will be called when the subprocess is finished. + Called when the child process exits and all file descriptors + associated with it have been closed. @type reason: L{twisted.python.failure.Failure} """ diff -Nru twisted-12.0.0/twisted/internet/reactor.py twisted-12.2.0/twisted/internet/reactor.py --- twisted-12.0.0/twisted/internet/reactor.py 2011-05-05 02:48:02.000000000 +0000 +++ twisted-12.2.0/twisted/internet/reactor.py 2012-05-14 22:39:50.000000000 +0000 @@ -6,10 +6,10 @@ applications using Twisted. The reactor provides APIs for networking, threading, dispatching events, and more. -The default reactor is based on C{select(2)} and will be installed if this -module is imported without another reactor being explicitly installed. -Regardless of which reactor is installed, importing this module is the correct -way to get a reference to it. +The default reactor depends on the platform and will be installed if this +module is imported without another reactor being explicitly installed +beforehand. Regardless of which reactor is installed, importing this module is +the correct way to get a reference to it. New application code should prefer to pass and accept the reactor as a parameter where it is needed, rather than relying on being able to import this diff -Nru twisted-12.0.0/twisted/internet/stdio.py twisted-12.2.0/twisted/internet/stdio.py --- twisted-12.0.0/twisted/internet/stdio.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/internet/stdio.py 2012-06-28 15:47:04.000000000 +0000 @@ -25,8 +25,11 @@ from twisted.python.runtime import platform if platform.isWindows(): - from twisted.internet._win32stdio import StandardIO + from twisted.internet import _win32stdio + StandardIO = _win32stdio.StandardIO + PipeAddress = _win32stdio.Win32PipeAddress + else: - from twisted.internet._posixstdio import StandardIO + from twisted.internet._posixstdio import StandardIO, PipeAddress -__all__ = ['StandardIO'] +__all__ = ['StandardIO', 'PipeAddress'] diff -Nru twisted-12.0.0/twisted/internet/task.py twisted-12.2.0/twisted/internet/task.py --- twisted-12.0.0/twisted/internet/task.py 2012-01-15 21:19:39.000000000 +0000 +++ twisted-12.2.0/twisted/internet/task.py 2012-06-17 16:54:37.000000000 +0000 @@ -646,6 +646,10 @@ Cooperatively iterate over the given iterator, dividing runtime between it and all other iterators which have been passed to this function and not yet exhausted. + + @param iterator: the iterator to invoke. + + @return: a Deferred that will fire when the iterator finishes. """ return _theCooperator.coiterate(iterator) diff -Nru twisted-12.0.0/twisted/internet/tcp.py twisted-12.2.0/twisted/internet/tcp.py --- twisted-12.0.0/twisted/internet/tcp.py 2011-12-11 03:20:29.000000000 +0000 +++ twisted-12.2.0/twisted/internet/tcp.py 2012-07-28 14:29:16.000000000 +0000 @@ -85,16 +85,20 @@ from os import strerror + from errno import errorcode # Twisted Imports from twisted.internet import base, address, fdesc from twisted.internet.task import deferLater from twisted.python import log, failure, reflect -from twisted.python.util import unsignedID +from twisted.python.util import unsignedID, untilConcludes from twisted.internet.error import CannotListenError from twisted.internet import abstract, main, interfaces, error +# Not all platforms have, or support, this flag. +_AI_NUMERICSERV = getattr(socket, "AI_NUMERICSERV", 0) + class _SocketCloser(object): @@ -108,7 +112,8 @@ skt = self.socket try: if orderly: - getattr(skt, self._socketShutdownMethod)(2) + if self._socketShutdownMethod is not None: + getattr(skt, self._socketShutdownMethod)(2) else: # Set SO_LINGER to 1,0 which, by convention, causes a # connection reset to be sent when close is called, @@ -194,6 +199,11 @@ return else: return main.CONNECTION_LOST + + return self._dataReceived(data) + + + def _dataReceived(self, data): if not data: return main.CONNECTION_DONE rval = self.protocol.dataReceived(data) @@ -217,14 +227,14 @@ connection is lost, an exception is returned. Otherwise, the number of bytes successfully written is returned. """ + # Limit length of buffer to try to send, because some OSes are too + # stupid to do so themselves (ahem windows) + limitedData = buffer(data, 0, self.SEND_LIMIT) + try: - # Limit length of buffer to try to send, because some OSes are too - # stupid to do so themselves (ahem windows) - return self.socket.send(buffer(data, 0, self.SEND_LIMIT)) + return untilConcludes(self.socket.send, limitedData) except socket.error, se: - if se.args[0] == EINTR: - return self.writeSomeData(data) - elif se.args[0] in (EWOULDBLOCK, ENOBUFS): + if se.args[0] in (EWOULDBLOCK, ENOBUFS): return 0 else: return main.CONNECTION_LOST @@ -299,30 +309,124 @@ -class BaseClient(_TLSClientMixin, Connection): + +class _BaseBaseClient(object): """ - A base class for client TCP (and similiar) sockets. + Code shared with other (non-POSIX) reactors for management of general + outgoing connections. + + Requirements upon subclasses are documented as instance variables rather + than abstract methods, in order to avoid MRO confusion, since this base is + mixed in to unfortunately weird and distinctive multiple-inheritance + hierarchies and many of these attributes are provided by peer classes + rather than descendant classes in those hierarchies. + + @ivar addressFamily: The address family constant (C{socket.AF_INET}, + C{socket.AF_INET6}, C{socket.AF_UNIX}) of the underlying socket of this + client connection. + @type addressFamily: C{int} + + @ivar socketType: The socket type constant (C{socket.SOCK_STREAM} or + C{socket.SOCK_DGRAM}) of the underlying socket. + @type socketType: C{int} + + @ivar _requiresResolution: A flag indicating whether the address of this + client will require name resolution. C{True} if the hostname of said + address indicates a name that must be resolved by hostname lookup, + C{False} if it indicates an IP address literal. + @type _requiresResolution: C{bool} + + @cvar _commonConnection: Subclasses must provide this attribute, which + indicates the L{Connection}-alike class to invoke C{__init__} and + C{connectionLost} on. + @type _commonConnection: C{type} + + @ivar _stopReadingAndWriting: Subclasses must implement in order to remove + this transport from its reactor's notifications in response to a + terminated connection attempt. + @type _stopReadingAndWriting: 0-argument callable returning C{None} + + @ivar _closeSocket: Subclasses must implement in order to close the socket + in response to a terminated connection attempt. + @type _closeSocket: 1-argument callable; see L{_SocketCloser._closeSocket} + + @ivar _collectSocketDetails: Clean up references to the attached socket in + its underlying OS resource (such as a file descriptor or file handle), + as part of post connection-failure cleanup. + @type _collectSocketDetails: 0-argument callable returning C{None}. + + @ivar reactor: The class pointed to by C{_commonConnection} should set this + attribute in its constructor. + @type reactor: L{twisted.internet.interfaces.IReactorTime}, + L{twisted.internet.interfaces.IReactorCore}, + L{twisted.internet.interfaces.IReactorFDSet} """ - _base = Connection addressFamily = socket.AF_INET socketType = socket.SOCK_STREAM def _finishInit(self, whenDone, skt, error, reactor): """ - Called by base classes to continue to next stage of initialization. + Called by subclasses to continue to the stage of initialization where + the socket connect attempt is made. + + @param whenDone: A 0-argument callable to invoke once the connection is + set up. This is C{None} if the connection could not be prepared + due to a previous error. + + @param skt: The socket object to use to perform the connection. + @type skt: C{socket._socketobject} + + @param error: The error to fail the connection with. + + @param reactor: The reactor to use for this client. + @type reactor: L{twisted.internet.interfaces.IReactorTime} """ if whenDone: - Connection.__init__(self, skt, None, reactor) - self.doWrite = self.doConnect - self.doRead = self.doConnect + self._commonConnection.__init__(self, skt, None, reactor) reactor.callLater(0, whenDone) else: reactor.callLater(0, self.failIfNotConnected, error) - def stopConnecting(self): - """Stop attempt to connect.""" - self.failIfNotConnected(error.UserError()) + + def resolveAddress(self): + """ + Resolve the name that was passed to this L{_BaseBaseClient}, if + necessary, and then move on to attempting the connection once an + address has been determined. (The connection will be attempted + immediately within this function if either name resolution can be + synchronous or the address was an IP address literal.) + + @note: You don't want to call this method from outside, as it won't do + anything useful; it's just part of the connection bootstrapping + process. Also, although this method is on L{_BaseBaseClient} for + historical reasons, it's not used anywhere except for L{Client} + itself. + + @return: C{None} + """ + if self._requiresResolution: + d = self.reactor.resolve(self.addr[0]) + d.addCallback(lambda n: (n,) + self.addr[1:]) + d.addCallbacks(self._setRealAddress, self.failIfNotConnected) + else: + self._setRealAddress(self.addr) + + + def _setRealAddress(self, address): + """ + Set the resolved address of this L{_BaseBaseClient} and initiate the + connection attempt. + + @param address: Depending on whether this is an IPv4 or IPv6 connection + attempt, a 2-tuple of C{(host, port)} or a 4-tuple of C{(host, + port, flow, scope)}. At this point it is a fully resolved address, + and the 'host' portion will always be an IP address, not a DNS + name. + """ + self.realAddress = address + self.doConnect() + def failIfNotConnected(self, err): """ @@ -334,19 +438,84 @@ not hasattr(self, "connector")): return + self._stopReadingAndWriting() + try: + self._closeSocket(True) + except AttributeError: + pass + else: + self._collectSocketDetails() self.connector.connectionFailed(failure.Failure(err)) + del self.connector + + + def stopConnecting(self): + """ + If a connection attempt is still outstanding (i.e. no connection is + yet established), immediately stop attempting to connect. + """ + self.failIfNotConnected(error.UserError()) + + + def connectionLost(self, reason): + """ + Invoked by lower-level logic when it's time to clean the socket up. + Depending on the state of the connection, either inform the attached + L{Connector} that the connection attempt has failed, or inform the + connected L{IProtocol} that the established connection has been lost. + + @param reason: the reason that the connection was terminated + @type reason: L{Failure} + """ + if not self.connected: + self.failIfNotConnected(error.ConnectError(string=reason)) + else: + self._commonConnection.connectionLost(self, reason) + self.connector.connectionLost(reason) + + + +class BaseClient(_BaseBaseClient, _TLSClientMixin, Connection): + """ + A base class for client TCP (and similiar) sockets. + + @ivar realAddress: The address object that will be used for socket.connect; + this address is an address tuple (the number of elements dependent upon + the address family) which does not contain any names which need to be + resolved. + @type realAddress: C{tuple} + + @ivar _base: L{Connection}, which is the base class of this class which has + all of the useful file descriptor methods. This is used by + L{_TLSServerMixin} to call the right methods to directly manipulate the + transport, as is necessary for writing TLS-encrypted bytes (whereas + those methods on L{Server} will go through another layer of TLS if it + has been enabled). + """ + + _base = Connection + _commonConnection = Connection + + def _stopReadingAndWriting(self): + """ + Implement the POSIX-ish (i.e. + L{twisted.internet.interfaces.IReactorFDSet}) method of detaching this + socket from the reactor for L{_BaseBaseClient}. + """ if hasattr(self, "reactor"): # this doesn't happen if we failed in __init__ self.stopReading() self.stopWriting() - del self.connector - try: - self._closeSocket(True) - except AttributeError: - pass - else: - del self.socket, self.fileno + + def _collectSocketDetails(self): + """ + Clean up references to the socket and its file descriptor. + + @see: L{_BaseBaseClient} + """ + del self.socket, self.fileno + def createInternetSocket(self): """(internal) Create a non-blocking socket using @@ -357,22 +526,16 @@ fdesc._setCloseOnExec(s.fileno()) return s - def resolveAddress(self): - if abstract.isIPAddress(self.addr[0]): - self._setRealAddress(self.addr[0]) - else: - d = self.reactor.resolve(self.addr[0]) - d.addCallbacks(self._setRealAddress, self.failIfNotConnected) - - def _setRealAddress(self, address): - self.realAddress = (address, self.addr[1]) - self.doConnect() def doConnect(self): - """I connect the socket. + """ + Initiate the outgoing connection attempt. - Then, call the protocol's makeConnection, and start waiting for data. + @note: Applications do not need to call this method; it will be invoked + internally as part of L{IReactorTCP.connectTCP}. """ + self.doWrite = self.doConnect + self.doRead = self.doConnect if not hasattr(self, "connector"): # this happens when connection failed but doConnect # was scheduled via a callLater in self._finishInit @@ -383,7 +546,6 @@ self.failIfNotConnected(error.getConnectError((err, strerror(err)))) return - # doConnect gets called twice. The first time we actually need to # start the connection attempt. The second time we don't really # want to (SO_ERROR above will have taken care of any errors, and if @@ -418,7 +580,18 @@ self.stopWriting() self._connectDone() + def _connectDone(self): + """ + This is a hook for when a connection attempt has succeeded. + + Here, we build the protocol from the + L{twisted.internet.protocol.ClientFactory} that was passed in, compute + a log string, begin reading so as to send traffic to the newly built + protocol, and finally hook up the protocol itself. + + This hook is overridden by L{ssl.Client} to initiate the TLS protocol. + """ self.protocol = self.connector.buildProtocol(self.getPeer()) self.connected = 1 logPrefix = self._getLogPrefix(self.protocol) @@ -426,16 +599,64 @@ self.startReading() self.protocol.makeConnection(self) - def connectionLost(self, reason): - if not self.connected: - self.failIfNotConnected(error.ConnectError(string=reason)) - else: - Connection.connectionLost(self, reason) - self.connector.connectionLost(reason) -class Client(BaseClient): - """A TCP client.""" +_NUMERIC_ONLY = socket.AI_NUMERICHOST | _AI_NUMERICSERV + +def _resolveIPv6(ip, port): + """ + Resolve an IPv6 literal into an IPv6 address. + + This is necessary to resolve any embedded scope identifiers to the relevant + C{sin6_scope_id} for use with C{socket.connect()}, C{socket.listen()}, or + C{socket.bind()}; see U{RFC 3493 } for + more information. + + @param ip: An IPv6 address literal. + @type ip: C{str} + + @param port: A port number. + @type port: C{int} + + @return: a 4-tuple of C{(host, port, flow, scope)}, suitable for use as an + IPv6 address. + + @raise socket.gaierror: if either the IP or port is not numeric as it + should be. + """ + return socket.getaddrinfo(ip, port, 0, 0, 0, _NUMERIC_ONLY)[0][4] + + + +class _BaseTCPClient(object): + """ + Code shared with other (non-POSIX) reactors for management of outgoing TCP + connections (both TCPv4 and TCPv6). + + @note: In order to be functional, this class must be mixed into the same + hierarchy as L{_BaseBaseClient}. It would subclass L{_BaseBaseClient} + directly, but the class hierarchy here is divided in strange ways out + of the need to share code along multiple axes; specifically, with the + IOCP reactor and also with UNIX clients in other reactors. + + @ivar _addressType: The Twisted _IPAddress implementation for this client + @type _addressType: L{IPv4Address} or L{IPv6Address} + + @ivar connector: The L{Connector} which is driving this L{_BaseTCPClient}'s + connection attempt. + + @ivar addr: The address that this socket will be connecting to. + @type addr: If IPv4, a 2-C{tuple} of C{(str host, int port)}. If IPv6, a + 4-C{tuple} of (C{str host, int port, int ignored, int scope}). + + @ivar createInternetSocket: Subclasses must implement this as a method to + create a python socket object of the appropriate address family and + socket type. + @type createInternetSocket: 0-argument callable returning + C{socket._socketobject}. + """ + + _addressType = address.IPv4Address def __init__(self, host, port, bindAddress, connector, reactor=None): # BaseClient.__init__ is invoked later @@ -446,6 +667,15 @@ err = None skt = None + if abstract.isIPAddress(host): + self._requiresResolution = False + elif abstract.isIPv6Address(host): + self._requiresResolution = False + self.addr = _resolveIPv6(host, port) + self.addressFamily = socket.AF_INET6 + self._addressType = address.IPv6Address + else: + self._requiresResolution = True try: skt = self.createInternetSocket() except socket.error, se: @@ -453,31 +683,52 @@ whenDone = None if whenDone and bindAddress is not None: try: - skt.bind(bindAddress) + if abstract.isIPv6Address(bindAddress[0]): + bindinfo = _resolveIPv6(*bindAddress) + else: + bindinfo = bindAddress + skt.bind(bindinfo) except socket.error, se: err = error.ConnectBindError(se.args[0], se.args[1]) whenDone = None self._finishInit(whenDone, skt, err, reactor) + def getHost(self): - """Returns an IPv4Address. + """ + Returns an L{IPv4Address} or L{IPv6Address}. This indicates the address from which I am connecting. """ - return address.IPv4Address('TCP', *self.socket.getsockname()) + return self._addressType('TCP', *self.socket.getsockname()[:2]) + def getPeer(self): - """Returns an IPv4Address. + """ + Returns an L{IPv4Address} or L{IPv6Address}. This indicates the address that I am connected to. """ - return address.IPv4Address('TCP', *self.realAddress) + # an ipv6 realAddress has more than two elements, but the IPv6Address + # constructor still only takes two. + return self._addressType('TCP', *self.realAddress[:2]) + def __repr__(self): s = '<%s to %s at %x>' % (self.__class__, self.addr, unsignedID(self)) return s + +class Client(_BaseTCPClient, BaseClient): + """ + A transport for a TCP protocol; either TCPv4 or TCPv6. + + Do not create these directly; use L{IReactorTCP.connectTCP}. + """ + + + class Server(_TLSServerMixin, Connection): """ Serverside socket-stream connection class. @@ -516,18 +767,60 @@ self.logstr = "%s,%s,%s" % (logPrefix, sessionno, self.hostname) - self.repstr = "<%s #%s on %s>" % (self.protocol.__class__.__name__, - self.sessionno, - self.server._realPortNumber) + if self.server is not None: + self.repstr = "<%s #%s on %s>" % (self.protocol.__class__.__name__, + self.sessionno, + self.server._realPortNumber) self.startReading() self.connected = 1 def __repr__(self): - """A string representation of this connection. + """ + A string representation of this connection. """ return self.repstr + @classmethod + def _fromConnectedSocket(cls, fileDescriptor, addressFamily, factory, + reactor): + """ + Create a new L{Server} based on an existing connected I{SOCK_STREAM} + socket. + + Arguments are the same as to L{Server.__init__}, except where noted. + + @param fileDescriptor: An integer file descriptor associated with a + connected socket. The socket must be in non-blocking mode. Any + additional attributes desired, such as I{FD_CLOEXEC}, must also be + set already. + + @param addressFamily: The address family (sometimes called I{domain}) + of the existing socket. For example, L{socket.AF_INET}. + + @return: A new instance of C{cls} wrapping the socket given by + C{fileDescriptor}. + """ + addressType = address.IPv4Address + if addressFamily == socket.AF_INET6: + addressType = address.IPv6Address + skt = socket.fromfd(fileDescriptor, addressFamily, socket.SOCK_STREAM) + addr = skt.getpeername() + protocolAddr = addressType('TCP', addr[0], addr[1]) + localPort = skt.getsockname()[1] + + protocol = factory.buildProtocol(protocolAddr) + if protocol is None: + skt.close() + return + + self = cls(skt, protocol, addr, None, addr[1], reactor) + self.repstr = "<%s #%s on %s>" % ( + self.protocol.__class__.__name__, self.sessionno, localPort) + protocol.makeConnection(self) + return self + + def getHost(self): """ Returns an L{IPv4Address} or L{IPv6Address}. @@ -577,6 +870,11 @@ this port. Normally this is C{"TCP"}, since this is a TCP port, but when the TLS implementation re-uses this class it overrides the value with C{"TLS"}. Only used for logging. + + @ivar _preexistingSocket: If not C{None}, a L{socket.socket} instance which + was created and initialized outside of the reactor and will be used to + listen for connections (instead of a new socket being created by this + L{Port}). """ implements(interfaces.IListeningPort) @@ -594,6 +892,10 @@ # value when we are actually listening. _realPortNumber = None + # An externally initialized socket that we will use, rather than creating + # our own. + _preexistingSocket = None + addressFamily = socket.AF_INET _addressType = address.IPv4Address @@ -610,10 +912,34 @@ self.interface = interface + @classmethod + def _fromListeningDescriptor(cls, reactor, fd, addressFamily, factory): + """ + Create a new L{Port} based on an existing listening I{SOCK_STREAM} + socket. + + Arguments are the same as to L{Port.__init__}, except where noted. + + @param fd: An integer file descriptor associated with a listening + socket. The socket must be in non-blocking mode. Any additional + attributes desired, such as I{FD_CLOEXEC}, must also be set already. + + @param addressFamily: The address family (sometimes called I{domain}) of + the existing socket. For example, L{socket.AF_INET}. + + @return: A new instance of C{cls} wrapping the socket given by C{fd}. + """ + port = socket.fromfd(fd, addressFamily, cls.socketType) + interface = port.getsockname()[0] + self = cls(None, factory, None, interface, reactor) + self._preexistingSocket = port + return self + + def __repr__(self): if self._realPortNumber is not None: - return "<%s of %s on %s>" % (self.__class__, self.factory.__class__, - self._realPortNumber) + return "<%s of %s on %s>" % (self.__class__, + self.factory.__class__, self._realPortNumber) else: return "<%s of %s (not listening)>" % (self.__class__, self.factory.__class__) @@ -630,15 +956,24 @@ This is called on unserialization, and must be called after creating a server to begin listening on the specified port. """ - try: - skt = self.createInternetSocket() - if self.addressFamily == socket.AF_INET6: - addr = socket.getaddrinfo(self.interface, self.port)[0][4] - else: - addr = (self.interface, self.port) - skt.bind(addr) - except socket.error, le: - raise CannotListenError, (self.interface, self.port, le) + if self._preexistingSocket is None: + # Create a new socket and make it listen + try: + skt = self.createInternetSocket() + if self.addressFamily == socket.AF_INET6: + addr = _resolveIPv6(self.interface, self.port) + else: + addr = (self.interface, self.port) + skt.bind(addr) + except socket.error, le: + raise CannotListenError, (self.interface, self.port, le) + skt.listen(self.backlog) + else: + # Re-use the externally specified socket + skt = self._preexistingSocket + self._preexistingSocket = None + # Avoid shutting it down at the end. + self._socketShutdownMethod = None # Make sure that if we listened on port 0, we update that to # reflect what the OS actually assigned us. @@ -647,10 +982,9 @@ log.msg("%s starting on %s" % ( self._getLogPrefix(self.factory), self._realPortNumber)) - # The order of the next 6 lines is kind of bizarre. If no one + # The order of the next 5 lines is kind of bizarre. If no one # can explain it, perhaps we should re-arrange them. self.factory.doStart() - skt.listen(self.backlog) self.connected = True self.socket = skt self.fileno = self.socket.fileno @@ -795,19 +1129,44 @@ class Connector(base.BaseConnector): + """ + A L{Connector} provides of L{twisted.internet.interfaces.IConnector} for + all POSIX-style reactors. + + @ivar _addressType: the type returned by L{Connector.getDestination}. + Either L{IPv4Address} or L{IPv6Address}, depending on the type of + address. + @type _addressType: C{type} + """ + _addressType = address.IPv4Address + def __init__(self, host, port, factory, timeout, bindAddress, reactor=None): - self.host = host if isinstance(port, types.StringTypes): try: port = socket.getservbyname(port, 'tcp') except socket.error, e: raise error.ServiceNameUnknownError(string="%s (%r)" % (e, port)) - self.port = port + self.host, self.port = host, port + if abstract.isIPv6Address(host): + self._addressType = address.IPv6Address self.bindAddress = bindAddress base.BaseConnector.__init__(self, factory, timeout, reactor) + def _makeTransport(self): + """ + Create a L{Client} bound to this L{Connector}. + + @return: a new L{Client} + @rtype: L{Client} + """ return Client(self.host, self.port, self.bindAddress, self, self.reactor) + def getDestination(self): - return address.IPv4Address('TCP', self.host, self.port) + """ + @see: L{twisted.internet.interfaces.IConnector.getDestination}. + """ + return self._addressType('TCP', self.host, self.port) + + diff -Nru twisted-12.0.0/twisted/internet/test/connectionmixins.py twisted-12.2.0/twisted/internet/test/connectionmixins.py --- twisted-12.0.0/twisted/internet/test/connectionmixins.py 2011-11-02 13:15:43.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/connectionmixins.py 2012-04-12 03:14:29.000000000 +0000 @@ -1,3 +1,4 @@ +# -*- test-case-name: twisted.internet.test.test_tcp -*- # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -5,14 +6,31 @@ Various helpers for tests for connection-oriented transports. """ +import socket + from gc import collect from weakref import ref +from zope.interface import implements +from zope.interface.verify import verifyObject + from twisted.python import context, log -from twisted.python.reflect import fullyQualifiedName +from twisted.python.failure import Failure +from twisted.python.runtime import platform from twisted.python.log import ILogContext, msg, err -from twisted.internet.defer import Deferred, gatherResults -from twisted.internet.protocol import ServerFactory, Protocol +from twisted.internet.defer import Deferred, gatherResults, succeed, fail +from twisted.internet.interfaces import ( + IConnector, IResolverSimple, IReactorFDSet) +from twisted.internet.protocol import ClientFactory, Protocol, ServerFactory +from twisted.test.test_tcp import ClosingProtocol +from twisted.trial.unittest import SkipTest +from twisted.internet.error import DNSLookupError +from twisted.internet.interfaces import ITLSTransport +from twisted.internet.test.reactormixins import ConnectableProtocol +from twisted.internet.test.reactormixins import runProtocolsWithReactor +from twisted.internet.test.reactormixins import needsRunningReactor + + def serverFactoryFor(protocol): """ @@ -29,6 +47,47 @@ # ServerFactory is good enough for client endpoints, too. factoryFor = serverFactoryFor + + +def findFreePort(interface='127.0.0.1', family=socket.AF_INET, + type=socket.SOCK_STREAM): + """ + Ask the platform to allocate a free port on the specified interface, then + release the socket and return the address which was allocated. + + @param interface: The local address to try to bind the port on. + @type interface: C{str} + + @param type: The socket type which will use the resulting port. + + @return: A two-tuple of address and port, like that returned by + L{socket.getsockname}. + """ + addr = socket.getaddrinfo(interface, 0)[0][4] + probe = socket.socket(family, type) + try: + probe.bind(addr) + return probe.getsockname() + finally: + probe.close() + + + +def _getWriters(reactor): + """ + Like L{IReactorFDSet.getWriters}, but with support for IOCP reactor as + well. + """ + if IReactorFDSet.providedBy(reactor): + return reactor.getWriters() + elif 'IOCP' in reactor.__class__.__name__: + return reactor.handles + else: + # Cannot tell what is going on. + raise Exception("Cannot find writers on %r" % (reactor,)) + + + class _AcceptOneClient(ServerFactory): """ This factory fires a L{Deferred} with a protocol instance shortly after it @@ -36,6 +95,7 @@ connected to a transport). @ivar reactor: The reactor used to schedule the I{shortly}. + @ivar result: A L{Deferred} which will be fired with the protocol instance. """ def __init__(self, reactor, result): @@ -50,7 +110,61 @@ -class ClosingLaterProtocol(Protocol): +class _SimplePullProducer(object): + """ + A pull producer which writes one byte whenever it is resumed. For use by + L{test_unregisterProducerAfterDisconnect}. + """ + def __init__(self, consumer): + self.consumer = consumer + + + def stopProducing(self): + pass + + + def resumeProducing(self): + log.msg("Producer.resumeProducing") + self.consumer.write('x') + + + +class Stop(ClientFactory): + """ + A client factory which stops a reactor when a connection attempt fails. + """ + failReason = None + + def __init__(self, reactor): + self.reactor = reactor + + + def clientConnectionFailed(self, connector, reason): + self.failReason = reason + msg("Stop(CF) cCFailed: %s" % (reason.getErrorMessage(),)) + self.reactor.stop() + + + +class FakeResolver(object): + """ + A resolver implementation based on a C{dict} mapping names to addresses. + """ + implements(IResolverSimple) + + def __init__(self, names): + self.names = names + + + def getHostByName(self, name, timeout): + try: + return succeed(self.names[name]) + except KeyError: + return fail(DNSLookupError("FakeResolver couldn't find " + name)) + + + +class ClosingLaterProtocol(ConnectableProtocol): """ ClosingLaterProtocol exchanges one byte with its peer and then disconnects itself. This is mostly a work-around for the fact that connectionMade is @@ -82,46 +196,9 @@ This mixin defines test methods which should apply to most L{ITransport} implementations. """ - def serverEndpoint(self, reactor): - """ - Return an object providing L{IStreamServerEndpoint} for use in creating - a server to use to establish the connection type to be tested. - """ - raise NotImplementedError("%s.serverEndpoint() not implemented" % ( - fullyQualifiedName(self.__class__),)) - - def clientEndpoint(self, reactor, serverAddress): - """ - Return an object providing L{IStreamClientEndpoint} for use in creating - a client to use to establish the connection type to be tested. - """ - raise NotImplementedError("%s.clientEndpoint() not implemented" % ( - fullyQualifiedName(self.__class__),)) - - - def loopback(self, reactor, clientProtocol, serverProtocol): - """ - Create a loopback connection of the type to be tested, using - C{clientProtocol} and C{serverProtocol} to handle each end of the - connection. - - @return: A L{Deferred} which fires when the connection is established. - The result is a two-tuple of the client protocol instance and - server protocol instance. - """ - accepted = Deferred() - factory = _AcceptOneClient(reactor, accepted) - factory.protocol = serverProtocol - server = self.serverEndpoint(reactor) - listening = server.listen(factory) - def startedListening(port): - address = port.getHost() - client = self.clientEndpoint(reactor, address) - return gatherResults([ - client.connect(factoryFor(clientProtocol)), accepted]) - listening.addCallback(startedListening) - return listening + # This should be a reactormixins.EndpointCreator instance. + endpoints = None def test_logPrefix(self): @@ -129,35 +206,30 @@ Client and server transports implement L{ILoggingContext.logPrefix} to return a message reflecting the protocol they are running. """ - class CustomLogPrefixProtocol(Protocol): + class CustomLogPrefixProtocol(ConnectableProtocol): def __init__(self, prefix): self._prefix = prefix - self.system = Deferred() + self.system = None + + def connectionMade(self): + self.transport.write("a") def logPrefix(self): return self._prefix def dataReceived(self, bytes): - self.system.callback(context.get(ILogContext)["system"]) - - reactor = self.buildReactor() - d = self.loopback( - reactor, - lambda: CustomLogPrefixProtocol("Custom Client"), - lambda: CustomLogPrefixProtocol("Custom Server")) - def connected((client, server)): - client.transport.write("foo") - server.transport.write("bar") - return gatherResults([client.system, server.system]) - d.addCallback(connected) - - def gotSystem((client, server)): - self.assertIn("Custom Client", client) - self.assertIn("Custom Server", server) - d.addCallback(gotSystem) - d.addErrback(err) - d.addCallback(lambda ignored: reactor.stop()) - self.runReactor(reactor) + self.system = context.get(ILogContext)["system"] + self.transport.write("b") + # Only close connection if both sides have received data, so + # that both sides have system set. + if "b" in bytes: + self.transport.loseConnection() + + client = CustomLogPrefixProtocol("Custom Client") + server = CustomLogPrefixProtocol("Custom Server") + runProtocolsWithReactor(self, server, client, self.endpoints) + self.assertIn("Custom Client", client.system) + self.assertIn("Custom Server", server.system) def test_writeAfterDisconnect(self): @@ -171,21 +243,19 @@ serverConnectionLostDeferred = Deferred() protocol = lambda: ClosingLaterProtocol(serverConnectionLostDeferred) - portDeferred = self.serverEndpoint(reactor).listen( + portDeferred = self.endpoints.server(reactor).listen( serverFactoryFor(protocol)) def listening(port): msg("Listening on %r" % (port.getHost(),)) - endpoint = self.clientEndpoint(reactor, port.getHost()) + endpoint = self.endpoints.client(reactor, port.getHost()) lostConnectionDeferred = Deferred() - protocol = lambda: ClosingLaterProtocol( - lostConnectionDeferred) + protocol = lambda: ClosingLaterProtocol(lostConnectionDeferred) client = endpoint.connect(factoryFor(protocol)) def write(proto): msg("About to write to %r" % (proto,)) proto.transport.write('x') - client.addCallbacks( - write, lostConnectionDeferred.errback) + client.addCallbacks(write, lostConnectionDeferred.errback) def disconnected(proto): msg("%r disconnected" % (proto,)) @@ -199,9 +269,11 @@ lostConnectionDeferred, serverConnectionLostDeferred]) - portDeferred.addCallback(listening) - portDeferred.addErrback(err) - portDeferred.addCallback(lambda ignored: reactor.stop()) + def onListen(): + portDeferred.addCallback(listening) + portDeferred.addErrback(err) + portDeferred.addCallback(lambda ignored: reactor.stop()) + needsRunningReactor(reactor, onListen) self.runReactor(reactor) self.assertEqual(finished, [True, True]) @@ -209,19 +281,19 @@ def test_protocolGarbageAfterLostConnection(self): """ - After the connection a protocol is being used for is closed, the reactor - discards all of its references to the protocol. + After the connection a protocol is being used for is closed, the + reactor discards all of its references to the protocol. """ lostConnectionDeferred = Deferred() clientProtocol = ClosingLaterProtocol(lostConnectionDeferred) clientRef = ref(clientProtocol) reactor = self.buildReactor() - portDeferred = self.serverEndpoint(reactor).listen( + portDeferred = self.endpoints.server(reactor).listen( serverFactoryFor(Protocol)) def listening(port): msg("Listening on %r" % (port.getHost(),)) - endpoint = self.clientEndpoint(reactor, port.getHost()) + endpoint = self.endpoints.client(reactor, port.getHost()) client = endpoint.connect(factoryFor(lambda: clientProtocol)) def disconnect(proto): @@ -231,9 +303,11 @@ client.addErrback(lostConnectionDeferred.errback) return lostConnectionDeferred - portDeferred.addCallback(listening) - portDeferred.addErrback(err) - portDeferred.addCallback(lambda ignored: reactor.stop()) + def onListening(): + portDeferred.addCallback(listening) + portDeferred.addErrback(err) + portDeferred.addBoth(lambda ignored: reactor.stop()) + needsRunningReactor(reactor, onListening) self.runReactor(reactor) @@ -254,3 +328,322 @@ log.addObserver(loggedMessages.append) self.addCleanup(log.removeObserver, loggedMessages.append) return loggedMessages + + + +class BrokenContextFactory(object): + """ + A context factory with a broken C{getContext} method, for exercising the + error handling for such a case. + """ + message = "Some path was wrong maybe" + + def getContext(self): + raise ValueError(self.message) + + + +class TCPClientTestsMixin(object): + """ + This mixin defines tests applicable to TCP client implementations. Classes + which mix this in must provide all of the documented instance variables in + order to specify how the test works. These are documented as instance + variables rather than declared as methods due to some peculiar inheritance + ordering concerns, but they are effectively abstract methods. + + This must be mixed in to a L{ReactorBuilder + } subclass, as it + depends on several of its methods. + + @ivar endpoints: A L{twisted.internet.test.reactormixins.EndpointCreator} + instance. + + @ivar interface: An IP address literal to locally bind a socket to as well + as to connect to. This can be any valid interface for the local host. + @type interface: C{str} + + @ivar port: An unused local listening port to listen on and connect to. + This will be used in conjunction with the C{interface}. (Depending on + what they're testing, some tests will locate their own port with + L{findFreePort} instead.) + @type port: C{int} + + @ivar family: an address family constant, such as L{socket.AF_INET}, + L{socket.AF_INET6}, or L{socket.AF_UNIX}, which indicates the address + family of the transport type under test. + @type family: C{int} + + @ivar addressClass: the L{twisted.internet.interfaces.IAddress} implementor + associated with the transport type under test. Must also be a + 3-argument callable which produces an instance of same. + @type addressClass: C{type} + + @ivar fakeDomainName: A fake domain name to use, to simulate hostname + resolution and to distinguish between hostnames and IP addresses where + necessary. + @type fakeDomainName: C{str} + """ + + def test_interface(self): + """ + L{IReactorTCP.connectTCP} returns an object providing L{IConnector}. + """ + reactor = self.buildReactor() + connector = reactor.connectTCP(self.interface, self.port, + ClientFactory()) + self.assertTrue(verifyObject(IConnector, connector)) + + + def test_clientConnectionFailedStopsReactor(self): + """ + The reactor can be stopped by a client factory's + C{clientConnectionFailed} method. + """ + host, port = findFreePort(self.interface, self.family)[:2] + reactor = self.buildReactor() + needsRunningReactor( + reactor, lambda: reactor.connectTCP(host, port, Stop(reactor))) + self.runReactor(reactor) + + + def test_addresses(self): + """ + A client's transport's C{getHost} and C{getPeer} return L{IPv4Address} + instances which have the dotted-quad string form of the resolved + adddress of the local and remote endpoints of the connection + respectively as their C{host} attribute, not the hostname originally + passed in to L{connectTCP + }, if a hostname + was used. + """ + host, port = findFreePort(self.interface, self.family)[:2] + reactor = self.buildReactor() + fakeDomain = self.fakeDomainName + reactor.installResolver(FakeResolver({fakeDomain: self.interface})) + + server = reactor.listenTCP( + 0, serverFactoryFor(Protocol), interface=host) + serverAddress = server.getHost() + + addresses = {'host': None, 'peer': None} + class CheckAddress(Protocol): + def makeConnection(self, transport): + addresses['host'] = transport.getHost() + addresses['peer'] = transport.getPeer() + reactor.stop() + + clientFactory = Stop(reactor) + clientFactory.protocol = CheckAddress + + def connectMe(): + reactor.connectTCP( + fakeDomain, server.getHost().port, clientFactory, + bindAddress=(self.interface, port)) + needsRunningReactor(reactor, connectMe) + + self.runReactor(reactor) + + if clientFactory.failReason: + self.fail(clientFactory.failReason.getTraceback()) + + self.assertEqual( + addresses['host'], + self.addressClass('TCP', self.interface, port)) + self.assertEqual( + addresses['peer'], + self.addressClass('TCP', self.interface, serverAddress.port)) + + + def test_connectEvent(self): + """ + This test checks that we correctly get notifications event for a + client. This ought to prevent a regression under Windows using the + GTK2 reactor. See #3925. + """ + reactor = self.buildReactor() + + server = reactor.listenTCP(0, serverFactoryFor(Protocol), + interface=self.interface) + connected = [] + + class CheckConnection(Protocol): + def connectionMade(self): + connected.append(self) + reactor.stop() + + clientFactory = Stop(reactor) + clientFactory.protocol = CheckConnection + + needsRunningReactor(reactor, lambda: reactor.connectTCP( + self.interface, server.getHost().port, clientFactory)) + + reactor.run() + + self.assertTrue(connected) + + + def test_unregisterProducerAfterDisconnect(self): + """ + If a producer is unregistered from a L{ITCPTransport} provider after + the transport has been disconnected (by the peer) and after + L{ITCPTransport.loseConnection} has been called, the transport is not + re-added to the reactor as a writer as would be necessary if the + transport were still connected. + """ + reactor = self.buildReactor() + port = reactor.listenTCP(0, serverFactoryFor(ClosingProtocol), + interface=self.interface) + + finished = Deferred() + finished.addErrback(log.err) + finished.addCallback(lambda ign: reactor.stop()) + + writing = [] + + class ClientProtocol(Protocol): + """ + Protocol to connect, register a producer, try to lose the + connection, wait for the server to disconnect from us, and then + unregister the producer. + """ + def connectionMade(self): + log.msg("ClientProtocol.connectionMade") + self.transport.registerProducer( + _SimplePullProducer(self.transport), False) + self.transport.loseConnection() + + def connectionLost(self, reason): + log.msg("ClientProtocol.connectionLost") + self.unregister() + writing.append(self.transport in _getWriters(reactor)) + finished.callback(None) + + def unregister(self): + log.msg("ClientProtocol unregister") + self.transport.unregisterProducer() + + clientFactory = ClientFactory() + clientFactory.protocol = ClientProtocol + reactor.connectTCP(self.interface, port.getHost().port, clientFactory) + self.runReactor(reactor) + self.assertFalse(writing[0], + "Transport was writing after unregisterProducer.") + + + def test_disconnectWhileProducing(self): + """ + If L{ITCPTransport.loseConnection} is called while a producer is + registered with the transport, the connection is closed after the + producer is unregistered. + """ + reactor = self.buildReactor() + + # For some reason, pyobject/pygtk will not deliver the close + # notification that should happen after the unregisterProducer call in + # this test. The selectable is in the write notification set, but no + # notification ever arrives. Probably for the same reason #5233 led + # win32eventreactor to be broken. + skippedReactors = ["Glib2Reactor", "Gtk2Reactor"] + reactorClassName = reactor.__class__.__name__ + if reactorClassName in skippedReactors and platform.isWindows(): + raise SkipTest( + "A pygobject/pygtk bug disables this functionality on Windows.") + + class Producer: + def resumeProducing(self): + log.msg("Producer.resumeProducing") + + port = reactor.listenTCP(0, serverFactoryFor(Protocol), + interface=self.interface) + + finished = Deferred() + finished.addErrback(log.err) + finished.addCallback(lambda ign: reactor.stop()) + + class ClientProtocol(Protocol): + """ + Protocol to connect, register a producer, try to lose the + connection, unregister the producer, and wait for the connection to + actually be lost. + """ + def connectionMade(self): + log.msg("ClientProtocol.connectionMade") + self.transport.registerProducer(Producer(), False) + self.transport.loseConnection() + # Let the reactor tick over, in case synchronously calling + # loseConnection and then unregisterProducer is the same as + # synchronously calling unregisterProducer and then + # loseConnection (as it is in several reactors). + reactor.callLater(0, reactor.callLater, 0, self.unregister) + + def unregister(self): + log.msg("ClientProtocol unregister") + self.transport.unregisterProducer() + # This should all be pretty quick. Fail the test + # if we don't get a connectionLost event really + # soon. + reactor.callLater( + 1.0, finished.errback, + Failure(Exception("Connection was not lost"))) + + def connectionLost(self, reason): + log.msg("ClientProtocol.connectionLost") + finished.callback(None) + + clientFactory = ClientFactory() + clientFactory.protocol = ClientProtocol + reactor.connectTCP(self.interface, port.getHost().port, clientFactory) + self.runReactor(reactor) + # If the test failed, we logged an error already and trial + # will catch it. + + + def test_badContext(self): + """ + If the context factory passed to L{ITCPTransport.startTLS} raises an + exception from its C{getContext} method, that exception is raised by + L{ITCPTransport.startTLS}. + """ + reactor = self.buildReactor() + + brokenFactory = BrokenContextFactory() + results = [] + + serverFactory = ServerFactory() + serverFactory.protocol = Protocol + + port = reactor.listenTCP(0, serverFactory, interface=self.interface) + endpoint = self.endpoints.client(reactor, port.getHost()) + + clientFactory = ClientFactory() + clientFactory.protocol = Protocol + connectDeferred = endpoint.connect(clientFactory) + + def connected(protocol): + if not ITLSTransport.providedBy(protocol.transport): + results.append("skip") + else: + results.append(self.assertRaises(ValueError, + protocol.transport.startTLS, + brokenFactory)) + + def connectFailed(failure): + results.append(failure) + + def whenRun(): + connectDeferred.addCallback(connected) + connectDeferred.addErrback(connectFailed) + connectDeferred.addBoth(lambda ign: reactor.stop()) + needsRunningReactor(reactor, whenRun) + + self.runReactor(reactor) + + self.assertEqual(len(results), 1, + "more than one callback result: %s" % (results,)) + + if isinstance(results[0], Failure): + # self.fail(Failure) + results[0].raiseException() + if results[0] == "skip": + raise SkipTest("Reactor does not support ITLSTransport") + self.assertEqual(BrokenContextFactory.message, str(results[0])) diff -Nru twisted-12.0.0/twisted/internet/test/reactormixins.py twisted-12.2.0/twisted/internet/test/reactormixins.py --- twisted-12.0.0/twisted/internet/test/reactormixins.py 2011-08-28 15:09:23.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/reactormixins.py 2012-04-12 03:14:29.000000000 +0000 @@ -7,9 +7,10 @@ __metaclass__ = type -import signal +import os, signal, time -from twisted.internet.defer import TimeoutError +from twisted.internet.defer import TimeoutError, Deferred, gatherResults +from twisted.internet.protocol import ClientFactory, Protocol from twisted.trial.unittest import TestCase, SkipTest from twisted.python.runtime import platform from twisted.python.reflect import namedAny, fullyQualifiedName @@ -23,6 +24,159 @@ from twisted.internet import process + +def needsRunningReactor(reactor, thunk): + """ + Various functions within these tests need an already-running reactor at + some point. They need to stop the reactor when the test has completed, and + that means calling reactor.stop(). However, reactor.stop() raises an + exception if the reactor isn't already running, so if the L{Deferred} that + a particular API under test returns fires synchronously (as especially an + endpoint's C{connect()} method may do, if the connect is to a local + interface address) then the test won't be able to stop the reactor being + tested and finish. So this calls C{thunk} only once C{reactor} is running. + + (This is just an alias for + L{twisted.internet.interfaces.IReactorCore.callWhenRunning} on the given + reactor parameter, in order to centrally reference the above paragraph and + repeating it everywhere as a comment.) + + @param reactor: the L{twisted.internet.interfaces.IReactorCore} under test + + @param thunk: a 0-argument callable, which eventually finishes the test in + question, probably in a L{Deferred} callback. + """ + reactor.callWhenRunning(thunk) + + + +class ConnectableProtocol(Protocol): + """ + A protocol to be used with L{runProtocolsWithReactor}. + + The protocol and its pair should eventually disconnect from each other. + + @ivar reactor: The reactor used in this test. + + @ivar disconnectReason: The L{Failure} passed to C{connectionLost}. + + @ivar _done: A L{Deferred} which will be fired when the connection is + lost. + """ + + disconnectReason = None + + def _setAttributes(self, reactor, done): + """ + Set attributes on the protocol that are known only externally; this + will be called by L{runProtocolsWithReactor} when this protocol is + instantiated. + + @param reactor: The reactor used in this test. + + @param done: A L{Deferred} which will be fired when the connection is + lost. + """ + self.reactor = reactor + self._done = done + + + def connectionLost(self, reason): + self.disconnectReason = reason + self._done.callback(None) + del self._done + + + +class EndpointCreator: + """ + Create client and server endpoints that know how to connect to each other. + """ + + def server(self, reactor): + """ + Return an object providing C{IStreamServerEndpoint} for use in creating + a server to use to establish the connection type to be tested. + """ + raise NotImplementedError() + + + def client(self, reactor, serverAddress): + """ + Return an object providing C{IStreamClientEndpoint} for use in creating + a client to use to establish the connection type to be tested. + """ + raise NotImplementedError() + + + +class _SingleProtocolFactory(ClientFactory): + """ + Factory to be used by L{runProtocolsWithReactor}. + + It always returns the same protocol (i.e. is intended for only a single connection). + """ + + def __init__(self, protocol): + self._protocol = protocol + + + def buildProtocol(self, addr): + return self._protocol + + + +def runProtocolsWithReactor(reactorBuilder, serverProtocol, clientProtocol, + endpointCreator): + """ + Connect two protocols using endpoints and a new reactor instance. + + A new reactor will be created and run, with the client and server protocol + instances connected to each other using the given endpoint creator. The + protocols should run through some set of tests, then disconnect; when both + have disconnected the reactor will be stopped and the function will + return. + + @param reactorBuilder: A L{ReactorBuilder} instance. + + @param serverProtocol: A L{ConnectableProtocol} that will be the server. + + @param clientProtocol: A L{ConnectableProtocol} that will be the client. + + @param endpointCreator: An instance of L{EndpointCreator}. + + @return: The reactor run by this test. + """ + reactor = reactorBuilder.buildReactor() + serverProtocol._setAttributes(reactor, Deferred()) + clientProtocol._setAttributes(reactor, Deferred()) + serverFactory = _SingleProtocolFactory(serverProtocol) + clientFactory = _SingleProtocolFactory(clientProtocol) + + # Listen on a port: + serverEndpoint = endpointCreator.server(reactor) + d = serverEndpoint.listen(serverFactory) + + # Connect to the port: + def gotPort(p): + clientEndpoint = endpointCreator.client( + reactor, p.getHost()) + return clientEndpoint.connect(clientFactory) + d.addCallback(gotPort) + + # Stop reactor when both connections are lost: + def failed(result): + log.err(result, "Connection setup failed.") + disconnected = gatherResults([serverProtocol._done, clientProtocol._done]) + d.addCallback(lambda _: disconnected) + d.addErrback(failed) + d.addCallback(lambda _: needsRunningReactor(reactor, reactor.stop)) + + reactorBuilder.runReactor(reactor) + return reactor + + + class ReactorBuilder: """ L{TestCase} mixin which provides a reactor-creation API. This mixin @@ -57,19 +211,29 @@ # since no one really wants to use it on other platforms. _reactors.extend([ "twisted.internet.gtk2reactor.PortableGtkReactor", + "twisted.internet.gireactor.PortableGIReactor", + "twisted.internet.gtk3reactor.PortableGtk3Reactor", "twisted.internet.win32eventreactor.Win32Reactor", "twisted.internet.iocpreactor.reactor.IOCPReactor"]) else: _reactors.extend([ "twisted.internet.glib2reactor.Glib2Reactor", "twisted.internet.gtk2reactor.Gtk2Reactor", - "twisted.internet.kqreactor.KQueueReactor"]) + "twisted.internet.gireactor.GIReactor", + "twisted.internet.gtk3reactor.Gtk3Reactor"]) if platform.isMacOSX(): _reactors.append("twisted.internet.cfreactor.CFReactor") else: _reactors.extend([ "twisted.internet.pollreactor.PollReactor", "twisted.internet.epollreactor.EPollReactor"]) + if not platform.isLinux(): + # Presumably Linux is not going to start supporting kqueue, so + # skip even trying this configuration. + _reactors.extend([ + # Support KQueue on non-OS-X POSIX platforms for now. + "twisted.internet.kqreactor.KQueueReactor", + ]) reactorFactory = None originalHandler = None @@ -93,12 +257,25 @@ if self.originalHandler is not None: signal.signal(signal.SIGCHLD, self.originalHandler) if process is not None: + begin = time.time() while process.reapProcessHandlers: log.msg( "ReactorBuilder.tearDown reaping some processes %r" % ( process.reapProcessHandlers,)) process.reapAllProcesses() + # The process should exit on its own. However, if it + # doesn't, we're stuck in this loop forever. To avoid + # hanging the test suite, eventually give the process some + # help exiting and move on. + time.sleep(0.001) + if time.time() - begin > 60: + for pid in process.reapProcessHandlers: + os.kill(pid, signal.SIGKILL) + raise Exception( + "Timeout waiting for child processes to exit: %r" % ( + process.reapProcessHandlers,)) + def unbuildReactor(self, reactor): """ diff -Nru twisted-12.0.0/twisted/internet/test/test_address.py twisted-12.2.0/twisted/internet/test/test_address.py --- twisted-12.0.0/twisted/internet/test/test_address.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_address.py 2012-04-24 21:19:37.000000000 +0000 @@ -89,7 +89,10 @@ when a different name is passed in """ self.assertFalse(self.buildAddress() == self.buildDifferentAddress()) + self.assertFalse(self.buildDifferentAddress() == self.buildAddress()) + self.assertTrue(self.buildAddress() != self.buildDifferentAddress()) + self.assertTrue(self.buildDifferentAddress() != self.buildAddress()) def assertDeprecations(self, testMethod, message): @@ -131,10 +134,12 @@ If a value is passed for the C{_bwHack} parameter to L{IPv4Address}, a deprecation warning is emitted. """ + # Construct this for warning side-effects, disregard the actual object. + IPv4Address("TCP", "127.0.0.3", 0, _bwHack="TCP") + message = ( "twisted.internet.address.IPv4Address._bwHack is deprecated " "since Twisted 11.0") - address = IPv4Address("TCP", "127.0.0.3", 0, _bwHack="TCP") return self.assertDeprecations(self.test_bwHackDeprecation, message) @@ -161,10 +166,12 @@ If a value is passed for the C{_bwHack} parameter to L{IPv4Address}, a deprecation warning is emitted. """ + # Construct this for warning side-effects, disregard the actual object. + IPv4Address("UDP", "127.0.0.3", 0, _bwHack="UDP") + message = ( "twisted.internet.address.IPv4Address._bwHack is deprecated " "since Twisted 11.0") - address = IPv4Address("UDP", "127.0.0.3", 0, _bwHack="UDP") return self.assertDeprecations(self.test_bwHackDeprecation, message) @@ -201,6 +208,8 @@ os.symlink(os.path.abspath(self._socketAddress), linkName) self.assertTrue( UNIXAddress(self._socketAddress) == UNIXAddress(linkName)) + self.assertTrue( + UNIXAddress(linkName) == UNIXAddress(self._socketAddress)) test_comparisonOfLinkedFiles.skip = symlinkSkip @@ -221,8 +230,63 @@ If a value is passed for the C{_bwHack} parameter to L{UNIXAddress}, a deprecation warning is emitted. """ + # Construct this for warning side-effects, disregard the actual object. + UNIXAddress(self.mktemp(), _bwHack='UNIX') + message = ( "twisted.internet.address.UNIXAddress._bwHack is deprecated " "since Twisted 11.0") - address = UNIXAddress(self.mktemp(), _bwHack='UNIX') return self.assertDeprecations(self.test_bwHackDeprecation, message) + + + +class EmptyUNIXAddressTestCase(unittest.TestCase, AddressTestCaseMixin): + """ + Tests for L{UNIXAddress} operations involving a C{None} address. + """ + addressArgSpec = (("name", "%r"),) + + def setUp(self): + self._socketAddress = self.mktemp() + + + def buildAddress(self): + """ + Create an arbitrary new L{UNIXAddress} instance. A new instance is + created for each call, but always for the same address. + """ + return UNIXAddress(self._socketAddress) + + + def buildDifferentAddress(self): + """ + Like L{buildAddress}, but with a fixed address of C{None}. + """ + return UNIXAddress(None) + + + def test_comparisonOfLinkedFiles(self): + """ + A UNIXAddress referring to a C{None} address does not compare equal to a + UNIXAddress referring to a symlink. + """ + linkName = self.mktemp() + self.fd = open(self._socketAddress, 'w') + os.symlink(os.path.abspath(self._socketAddress), linkName) + self.assertTrue( + UNIXAddress(self._socketAddress) != UNIXAddress(None)) + self.assertTrue( + UNIXAddress(None) != UNIXAddress(self._socketAddress)) + test_comparisonOfLinkedFiles.skip = symlinkSkip + + + def test_emptyHash(self): + """ + C{__hash__} can be used to get a hash of an address, even one referring + to C{None} rather than a real path. + """ + addr = self.buildDifferentAddress() + d = {addr: True} + self.assertTrue(d[self.buildDifferentAddress()]) + + diff -Nru twisted-12.0.0/twisted/internet/test/test_core.py twisted-12.2.0/twisted/internet/test/test_core.py --- twisted-12.0.0/twisted/internet/test/test_core.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_core.py 2012-05-12 13:55:41.000000000 +0000 @@ -134,15 +134,15 @@ reactor.addSystemEventTrigger("before", "startup", beforeStartup) reactor.addSystemEventTrigger("after", "startup", afterStartup) - sawPhase = [None] + sawPhase = [] def fakeSignal(signum, action): - sawPhase[0] = phase[0] + sawPhase.append(phase[0]) self.patch(signal, 'signal', fakeSignal) reactor.callWhenRunning(reactor.stop) self.assertEqual(phase[0], None) - self.assertEqual(sawPhase[0], None) + self.assertEqual(sawPhase, []) self.runReactor(reactor) - self.assertEqual(sawPhase[0], "before") + self.assertIn("before", sawPhase) self.assertEqual(phase[0], "after") diff -Nru twisted-12.0.0/twisted/internet/test/test_default.py twisted-12.2.0/twisted/internet/test/test_default.py --- twisted-12.0.0/twisted/internet/test/test_default.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_default.py 2012-05-08 00:03:40.000000000 +0000 @@ -5,17 +5,12 @@ Tests for L{twisted.internet.default}. """ -try: - from select import poll -except ImportError: - pollSkip = "select.poll() unavailable on this platform" -else: - pollSkip = None - +import select from twisted.trial.unittest import TestCase from twisted.python.runtime import Platform from twisted.internet.default import _getInstallFunction +unix = Platform('posix', 'other') linux = Platform('posix', 'linux2') windows = Platform('nt', 'win32') osx = Platform('posix', 'darwin') @@ -24,17 +19,44 @@ class PollReactorTests(TestCase): """ Tests for the cases of L{twisted.internet.default._getInstallFunction} - in which it picks the poll(2)-based reactor. + in which it picks the poll(2) or epoll(7)-based reactors. """ - skip = pollSkip + + def assertIsPoll(self, install): + """ + Assert the given function will install the poll() reactor, or select() + if poll() is unavailable. + """ + if hasattr(select, "poll"): + self.assertEqual( + install.__module__, 'twisted.internet.pollreactor') + else: + self.assertEqual( + install.__module__, 'twisted.internet.selectreactor') + + + def test_unix(self): + """ + L{_getInstallFunction} chooses the poll reactor on arbitrary Unix + platforms, falling back to select(2) if it is unavailable. + """ + install = _getInstallFunction(unix) + self.assertIsPoll(install) + def test_linux(self): """ - L{_getInstallFunction} chooses the poll reactor on Linux. + L{_getInstallFunction} chooses the epoll reactor on Linux, or poll if + epoll is unavailable. """ install = _getInstallFunction(linux) - self.assertEqual( - install.__module__, 'twisted.internet.pollreactor') + try: + from twisted.internet import epollreactor + except ImportError: + self.assertIsPoll(install) + else: + self.assertEqual( + install.__module__, 'twisted.internet.epollreactor') diff -Nru twisted-12.0.0/twisted/internet/test/test_endpoints.py twisted-12.2.0/twisted/internet/test/test_endpoints.py --- twisted-12.0.0/twisted/internet/test/test_endpoints.py 2011-10-11 11:43:33.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_endpoints.py 2012-08-04 11:59:34.000000000 +0000 @@ -5,21 +5,29 @@ L{IReactorSSL}, and L{IReactorUNIX} interfaces found in L{twisted.internet.endpoints}. """ - from errno import EPERM +from socket import AF_INET, AF_INET6, SOCK_STREAM, IPPROTO_TCP from zope.interface import implements +from zope.interface.verify import verifyObject from twisted.trial import unittest -from twisted.internet import error, interfaces +from twisted.internet import error, interfaces, defer from twisted.internet import endpoints -from twisted.internet.address import IPv4Address, UNIXAddress +from twisted.internet.address import IPv4Address, IPv6Address, UNIXAddress from twisted.internet.protocol import ClientFactory, Protocol -from twisted.test.proto_helpers import MemoryReactor, RaisingMemoryReactor +from twisted.test.proto_helpers import ( + MemoryReactor, RaisingMemoryReactor, StringTransport) from twisted.python.failure import Failure +from twisted.python.systemd import ListenFDs +from twisted.plugin import getPlugins from twisted import plugins from twisted.python.modules import getModule from twisted.python.filepath import FilePath +from twisted.protocols import basic +from twisted.internet import protocol, reactor, stdio +from twisted.internet.stdio import PipeAddress + pemPath = getModule("twisted.test").filePath.sibling("server.pem") casPath = getModule(__name__).filePath.sibling("fake_CAs") @@ -70,8 +78,14 @@ class TestHalfCloseableProtocol(TestProtocol): """ - A Protocol that implements L{IHalfCloseableProtocol} and records that - its C{readConnectionLost} and {writeConnectionLost} methods. + A Protocol that implements L{IHalfCloseableProtocol} and records whether its + C{readConnectionLost} and {writeConnectionLost} methods are called. + + @ivar readLost: A C{bool} indicating whether C{readConnectionLost} has been + called. + + @ivar writeLost: A C{bool} indicating whether C{writeConnectionLost} has + been called. """ implements(interfaces.IHalfCloseableProtocol) @@ -90,6 +104,26 @@ +class TestFileDescriptorReceiverProtocol(TestProtocol): + """ + A Protocol that implements L{IFileDescriptorReceiver} and records how its + C{fileDescriptorReceived} method is called. + + @ivar receivedDescriptors: A C{list} containing all of the file descriptors + passed to C{fileDescriptorReceived} calls made on this instance. + """ + implements(interfaces.IFileDescriptorReceiver) + + def connectionMade(self): + TestProtocol.connectionMade(self) + self.receivedDescriptors = [] + + + def fileDescriptorReceived(self, descriptor): + self.receivedDescriptors.append(descriptor) + + + class TestFactory(ClientFactory): """ Simple factory to be used both when connecting and listening. It contains @@ -111,7 +145,7 @@ C{doStart} method, allowing application-specific setup and logging. """ factory = ClientFactory() - wf = endpoints._WrappingFactory(factory, None) + wf = endpoints._WrappingFactory(factory) wf.doStart() self.assertEqual(1, factory.numPorts) @@ -123,7 +157,7 @@ """ factory = ClientFactory() factory.numPorts = 3 - wf = endpoints._WrappingFactory(factory, None) + wf = endpoints._WrappingFactory(factory) wf.doStop() self.assertEqual(2, factory.numPorts) @@ -143,7 +177,7 @@ raise ValueError("My protocol is poorly defined.") - wf = endpoints._WrappingFactory(BogusFactory(), None) + wf = endpoints._WrappingFactory(BogusFactory()) wf.buildProtocol(None) @@ -161,7 +195,7 @@ returned from the wrapped C{logPrefix} method is returned from L{_WrappingProtocol.logPrefix}. """ - wf = endpoints._WrappingFactory(TestFactory(), None) + wf = endpoints._WrappingFactory(TestFactory()) wp = wf.buildProtocol(None) self.assertEqual(wp.logPrefix(), "A Test Protocol") @@ -175,7 +209,7 @@ pass factory = TestFactory() factory.protocol = NoProtocol - wf = endpoints._WrappingFactory(factory, None) + wf = endpoints._WrappingFactory(factory) wp = wf.buildProtocol(None) self.assertEqual(wp.logPrefix(), "NoProtocol") @@ -185,7 +219,7 @@ The wrapped C{Protocol}'s C{dataReceived} will get called when our C{_WrappingProtocol}'s C{dataReceived} gets called. """ - wf = endpoints._WrappingFactory(TestFactory(), None) + wf = endpoints._WrappingFactory(TestFactory()) p = wf.buildProtocol(None) p.makeConnection(None) @@ -201,7 +235,7 @@ Our transport is properly hooked up to the wrappedProtocol when a connection is made. """ - wf = endpoints._WrappingFactory(TestFactory(), None) + wf = endpoints._WrappingFactory(TestFactory()) p = wf.buildProtocol(None) dummyTransport = object() @@ -219,7 +253,7 @@ L{_WrappingProtocol.connectionLost} is called. """ tf = TestFactory() - wf = endpoints._WrappingFactory(tf, None) + wf = endpoints._WrappingFactory(tf) p = wf.buildProtocol(None) p.connectionLost("fail") @@ -232,7 +266,7 @@ Calls to L{_WrappingFactory.clientConnectionLost} should errback the L{_WrappingFactory._onConnection} L{Deferred} """ - wf = endpoints._WrappingFactory(TestFactory(), None) + wf = endpoints._WrappingFactory(TestFactory()) expectedFailure = Failure(error.ConnectError(string="fail")) wf.clientConnectionFailed( @@ -248,10 +282,46 @@ self.assertEqual(errors, [expectedFailure]) + def test_wrappingProtocolFileDescriptorReceiver(self): + """ + Our L{_WrappingProtocol} should be an L{IFileDescriptorReceiver} if the + wrapped protocol is. + """ + connectedDeferred = None + applicationProtocol = TestFileDescriptorReceiverProtocol() + wrapper = endpoints._WrappingProtocol( + connectedDeferred, applicationProtocol) + self.assertTrue(interfaces.IFileDescriptorReceiver.providedBy(wrapper)) + self.assertTrue(verifyObject(interfaces.IFileDescriptorReceiver, wrapper)) + + + def test_wrappingProtocolNotFileDescriptorReceiver(self): + """ + Our L{_WrappingProtocol} does not provide L{IHalfCloseableProtocol} if + the wrapped protocol doesn't. + """ + tp = TestProtocol() + p = endpoints._WrappingProtocol(None, tp) + self.assertFalse(interfaces.IFileDescriptorReceiver.providedBy(p)) + + + def test_wrappedProtocolFileDescriptorReceived(self): + """ + L{_WrappingProtocol.fileDescriptorReceived} calls the wrapped protocol's + C{fileDescriptorReceived} method. + """ + wrappedProtocol = TestFileDescriptorReceiverProtocol() + wrapper = endpoints._WrappingProtocol( + defer.Deferred(), wrappedProtocol) + wrapper.makeConnection(StringTransport()) + wrapper.fileDescriptorReceived(42) + self.assertEqual(wrappedProtocol.receivedDescriptors, [42]) + + def test_wrappingProtocolHalfCloseable(self): """ - Our L{_WrappingProtocol} should be an L{IHalfCloseableProtocol} if - the C{wrappedProtocol} is. + Our L{_WrappingProtocol} should be an L{IHalfCloseableProtocol} if the + C{wrappedProtocol} is. """ cd = object() hcp = TestHalfCloseableProtocol() @@ -294,11 +364,10 @@ -class EndpointTestCaseMixin(object): +class ClientEndpointTestCaseMixin(object): """ - Generic test methods to be mixed into all endpoint test classes. + Generic test methods to be mixed into all client endpoint test classes. """ - def retrieveConnectedFactory(self, reactor): """ Retrieve a single factory that has connected using the given reactor. @@ -391,6 +460,11 @@ d.addErrback(checkFailure) d.cancel() + # When canceled, the connector will immediately notify its factory that + # the connection attempt has failed due to a UserError. + attemptFactory = self.retrieveConnectedFactory(mreactor) + attemptFactory.clientConnectionFailed(None, Failure(error.UserError())) + # This should be a feature of MemoryReactor: . self.assertEqual(len(receivedFailures), 1) @@ -400,6 +474,32 @@ self.assertEqual(failure.value.address, address) + def test_endpointConnectNonDefaultArgs(self): + """ + The endpoint should pass it's connectArgs parameter to the reactor's + listen methods. + """ + factory = object() + + mreactor = MemoryReactor() + + ep, expectedArgs, ignoredHost = self.createClientEndpoint( + mreactor, factory, + **self.connectArgs()) + + ep.connect(factory) + + expectedClients = self.expectedClients(mreactor) + + self.assertEqual(len(expectedClients), 1) + self.assertConnectArgs(expectedClients[0], expectedArgs) + + + +class ServerEndpointTestCaseMixin(object): + """ + Generic test methods to be mixed into all client endpoint test classes. + """ def test_endpointListenSuccess(self): """ An endpoint can listen and returns a deferred that gets called back @@ -449,52 +549,112 @@ self.assertEqual(receivedExceptions, [exception]) - def test_endpointConnectNonDefaultArgs(self): + def test_endpointListenNonDefaultArgs(self): """ - The endpoint should pass it's connectArgs parameter to the reactor's + The endpoint should pass it's listenArgs parameter to the reactor's listen methods. """ factory = object() mreactor = MemoryReactor() - ep, expectedArgs, ignoredHost = self.createClientEndpoint( + ep, expectedArgs, ignoredHost = self.createServerEndpoint( mreactor, factory, - **self.connectArgs()) + **self.listenArgs()) - ep.connect(factory) + ep.listen(factory) - expectedClients = self.expectedClients(mreactor) + expectedServers = self.expectedServers(mreactor) - self.assertEqual(len(expectedClients), 1) - self.assertConnectArgs(expectedClients[0], expectedArgs) + self.assertEqual(expectedServers, [expectedArgs]) - def test_endpointListenNonDefaultArgs(self): + +class EndpointTestCaseMixin(ServerEndpointTestCaseMixin, + ClientEndpointTestCaseMixin): + """ + Generic test methods to be mixed into all endpoint test classes. + """ + + + +class StdioFactory(protocol.Factory): + protocol = basic.LineReceiver + + + +class StandardIOEndpointsTestCase(unittest.TestCase): + """ + Tests for Standard I/O Endpoints + """ + def setUp(self): + self.ep = endpoints.StandardIOEndpoint(reactor) + + + def test_standardIOInstance(self): """ - The endpoint should pass it's listenArgs parameter to the reactor's - listen methods. + The endpoint creates an L{endpoints.StandardIO} instance. """ - factory = object() + self.d = self.ep.listen(StdioFactory()) + def checkInstanceAndLoseConnection(stdioOb): + self.assertIsInstance(stdioOb, stdio.StandardIO) + stdioOb.loseConnection() + self.d.addCallback(checkInstanceAndLoseConnection) + return self.d - mreactor = MemoryReactor() - ep, expectedArgs, ignoredHost = self.createServerEndpoint( - mreactor, factory, - **self.listenArgs()) + def test_reactor(self): + """ + The reactor passed to the endpoint is set as its _reactor attribute. + """ + self.assertEqual(self.ep._reactor, reactor) - ep.listen(factory) - expectedServers = self.expectedServers(mreactor) + def test_protocol(self): + """ + The protocol used in the endpoint is a L{basic.LineReceiver} instance. + """ + self.d = self.ep.listen(StdioFactory()) + def checkProtocol(stdioOb): + from twisted.python.runtime import platform + if platform.isWindows(): + self.assertIsInstance(stdioOb.proto, basic.LineReceiver) + else: + self.assertIsInstance(stdioOb.protocol, basic.LineReceiver) + stdioOb.loseConnection() + self.d.addCallback(checkProtocol) + return self.d - self.assertEqual(expectedServers, [expectedArgs]) + def test_address(self): + """ + The address passed to the factory's buildProtocol in the endpoint + should be a PipeAddress instance. + """ + class TestAddrFactory(protocol.Factory): + protocol = basic.LineReceiver + _address = None + def buildProtocol(self, addr): + self._address = addr + p = self.protocol() + p.factory = self + return p + def getAddress(self): + return self._address + + myFactory = TestAddrFactory() + self.d = self.ep.listen(myFactory) + def checkAddress(stdioOb): + self.assertIsInstance(myFactory.getAddress(), PipeAddress) + stdioOb.loseConnection() + self.d.addCallback(checkAddress) + return self.d -class TCP4EndpointsTestCase(EndpointTestCaseMixin, - unittest.TestCase): + +class TCP4EndpointsTestCase(EndpointTestCaseMixin, unittest.TestCase): """ - Tests for TCP Endpoints. + Tests for TCP IPv4 Endpoints. """ def expectedServers(self, reactor): @@ -600,6 +760,216 @@ +class TCP6EndpointsTestCase(EndpointTestCaseMixin, unittest.TestCase): + """ + Tests for TCP IPv6 Endpoints. + """ + + def expectedServers(self, reactor): + """ + @return: List of calls to L{IReactorTCP.listenTCP} + """ + return reactor.tcpServers + + + def expectedClients(self, reactor): + """ + @return: List of calls to L{IReactorTCP.connectTCP} + """ + return reactor.tcpClients + + + def assertConnectArgs(self, receivedArgs, expectedArgs): + """ + Compare host, port, timeout, and bindAddress in C{receivedArgs} + to C{expectedArgs}. We ignore the factory because we don't + only care what protocol comes out of the + C{IStreamClientEndpoint.connect} call. + + @param receivedArgs: C{tuple} of (C{host}, C{port}, C{factory}, + C{timeout}, C{bindAddress}) that was passed to + L{IReactorTCP.connectTCP}. + @param expectedArgs: C{tuple} of (C{host}, C{port}, C{factory}, + C{timeout}, C{bindAddress}) that we expect to have been passed + to L{IReactorTCP.connectTCP}. + """ + (host, port, ignoredFactory, timeout, bindAddress) = receivedArgs + (expectedHost, expectedPort, _ignoredFactory, + expectedTimeout, expectedBindAddress) = expectedArgs + + self.assertEqual(host, expectedHost) + self.assertEqual(port, expectedPort) + self.assertEqual(timeout, expectedTimeout) + self.assertEqual(bindAddress, expectedBindAddress) + + + def connectArgs(self): + """ + @return: C{dict} of keyword arguments to pass to connect. + """ + return {'timeout': 10, 'bindAddress': ('localhost', 49595)} + + + def listenArgs(self): + """ + @return: C{dict} of keyword arguments to pass to listen + """ + return {'backlog': 100, 'interface': '::1'} + + + def createServerEndpoint(self, reactor, factory, **listenArgs): + """ + Create a L{TCP6ServerEndpoint} and return the values needed to verify + its behaviour. + + @param reactor: A fake L{IReactorTCP} that L{TCP6ServerEndpoint} can + call L{IReactorTCP.listenTCP} on. + @param factory: The thing that we expect to be passed to our + L{IStreamServerEndpoint.listen} implementation. + @param listenArgs: Optional dictionary of arguments to + L{IReactorTCP.listenTCP}. + """ + interface = listenArgs.get('interface', '::') + address = IPv6Address("TCP", interface, 0) + + if listenArgs is None: + listenArgs = {} + + return (endpoints.TCP6ServerEndpoint(reactor, + address.port, + **listenArgs), + (address.port, factory, + listenArgs.get('backlog', 50), + interface), + address) + + + def createClientEndpoint(self, reactor, clientFactory, **connectArgs): + """ + Create a L{TCP6ClientEndpoint} and return the values needed to verify + its behavior. + + @param reactor: A fake L{IReactorTCP} that L{TCP6ClientEndpoint} can + call L{IReactorTCP.connectTCP} on. + @param clientFactory: The thing that we expect to be passed to our + L{IStreamClientEndpoint.connect} implementation. + @param connectArgs: Optional dictionary of arguments to + L{IReactorTCP.connectTCP} + """ + address = IPv6Address("TCP", "::1", 80) + + return (endpoints.TCP6ClientEndpoint(reactor, + address.host, + address.port, + **connectArgs), + (address.host, address.port, clientFactory, + connectArgs.get('timeout', 30), + connectArgs.get('bindAddress', None)), + address) + + +class TCP6EndpointNameResolutionTestCase(ClientEndpointTestCaseMixin, + unittest.TestCase): + """ + Tests for a TCP IPv6 Client Endpoint pointed at a hostname instead + of an IPv6 address literal. + """ + + + def createClientEndpoint(self, reactor, clientFactory, **connectArgs): + """ + Create a L{TCP6ClientEndpoint} and return the values needed to verify + its behavior. + + @param reactor: A fake L{IReactorTCP} that L{TCP6ClientEndpoint} can + call L{IReactorTCP.connectTCP} on. + @param clientFactory: The thing that we expect to be passed to our + L{IStreamClientEndpoint.connect} implementation. + @param connectArgs: Optional dictionary of arguments to + L{IReactorTCP.connectTCP} + """ + address = IPv6Address("TCP", "::2", 80) + self.ep = endpoints.TCP6ClientEndpoint(reactor, + 'ipv6.example.com', + address.port, + **connectArgs) + + def testNameResolution(host): + self.assertEqual("ipv6.example.com", host) + data = [(AF_INET6, SOCK_STREAM, IPPROTO_TCP, '', ('::2', 0, 0, 0)), + (AF_INET6, SOCK_STREAM, IPPROTO_TCP, '', ('::3', 0, 0, 0)), + (AF_INET6, SOCK_STREAM, IPPROTO_TCP, '', ('::4', 0, 0, 0))] + return defer.succeed(data) + + self.ep._nameResolution = testNameResolution + + return (self.ep, + (address.host, address.port, clientFactory, + connectArgs.get('timeout', 30), + connectArgs.get('bindAddress', None)), + address) + + + def connectArgs(self): + """ + @return: C{dict} of keyword arguments to pass to connect. + """ + return {'timeout': 10, 'bindAddress': ('localhost', 49595)} + + + def expectedClients(self, reactor): + """ + @return: List of calls to L{IReactorTCP.connectTCP} + """ + return reactor.tcpClients + + + def assertConnectArgs(self, receivedArgs, expectedArgs): + """ + Compare host, port, timeout, and bindAddress in C{receivedArgs} + to C{expectedArgs}. We ignore the factory because we don't + only care what protocol comes out of the + C{IStreamClientEndpoint.connect} call. + + @param receivedArgs: C{tuple} of (C{host}, C{port}, C{factory}, + C{timeout}, C{bindAddress}) that was passed to + L{IReactorTCP.connectTCP}. + @param expectedArgs: C{tuple} of (C{host}, C{port}, C{factory}, + C{timeout}, C{bindAddress}) that we expect to have been passed + to L{IReactorTCP.connectTCP}. + """ + (host, port, ignoredFactory, timeout, bindAddress) = receivedArgs + (expectedHost, expectedPort, _ignoredFactory, + expectedTimeout, expectedBindAddress) = expectedArgs + + self.assertEqual(host, expectedHost) + self.assertEqual(port, expectedPort) + self.assertEqual(timeout, expectedTimeout) + self.assertEqual(bindAddress, expectedBindAddress) + + + def test_nameResolution(self): + """ + While resolving host names, _nameResolution calls + _deferToThread with _getaddrinfo. + """ + calls = [] + + def fakeDeferToThread(f, *args, **kwargs): + calls.append((f, args, kwargs)) + return defer.Deferred() + + endpoint = endpoints.TCP6ClientEndpoint(reactor, 'ipv6.example.com', + 1234) + fakegetaddrinfo = object() + endpoint._getaddrinfo = fakegetaddrinfo + endpoint._deferToThread = fakeDeferToThread + endpoint.connect(TestFactory()) + self.assertEqual( + [(fakegetaddrinfo, ("ipv6.example.com", 0, AF_INET6), {})], calls) + + + class SSL4EndpointsTestCase(EndpointTestCaseMixin, unittest.TestCase): """ @@ -1110,9 +1480,9 @@ def test_tcp(self): """ - When passed a TCP strports description, L{endpointClient} returns a - L{TCP4ClientEndpoint} instance initialized with the values from the - string. + When passed a TCP strports description, L{endpoints.clientFromString} + returns a L{TCP4ClientEndpoint} instance initialized with the values + from the string. """ reactor = object() client = endpoints.clientFromString( @@ -1126,6 +1496,53 @@ self.assertEqual(client._bindAddress, "10.0.0.2") + def test_tcpPositionalArgs(self): + """ + When passed a TCP strports description using positional arguments, + L{endpoints.clientFromString} returns a L{TCP4ClientEndpoint} instance + initialized with the values from the string. + """ + reactor = object() + client = endpoints.clientFromString( + reactor, + "tcp:example.com:1234:timeout=7:bindAddress=10.0.0.2") + self.assertIsInstance(client, endpoints.TCP4ClientEndpoint) + self.assertIdentical(client._reactor, reactor) + self.assertEqual(client._host, "example.com") + self.assertEqual(client._port, 1234) + self.assertEqual(client._timeout, 7) + self.assertEqual(client._bindAddress, "10.0.0.2") + + + def test_tcpHostPositionalArg(self): + """ + When passed a TCP strports description specifying host as a positional + argument, L{endpoints.clientFromString} returns a L{TCP4ClientEndpoint} + instance initialized with the values from the string. + """ + reactor = object() + + client = endpoints.clientFromString( + reactor, + "tcp:example.com:port=1234:timeout=7:bindAddress=10.0.0.2") + self.assertEqual(client._host, "example.com") + self.assertEqual(client._port, 1234) + + + def test_tcpPortPositionalArg(self): + """ + When passed a TCP strports description specifying port as a positional + argument, L{endpoints.clientFromString} returns a L{TCP4ClientEndpoint} + instance initialized with the values from the string. + """ + reactor = object() + client = endpoints.clientFromString( + reactor, + "tcp:host=example.com:1234:timeout=7:bindAddress=10.0.0.2") + self.assertEqual(client._host, "example.com") + self.assertEqual(client._port, 1234) + + def test_tcpDefaults(self): """ A TCP strports description may omit I{timeout} or I{bindAddress} to @@ -1141,9 +1558,9 @@ def test_unix(self): """ - When passed a UNIX strports description, L{endpointClient} returns a - L{UNIXClientEndpoint} instance initialized with the values from the - string. + When passed a UNIX strports description, L{endpoints.clientFromString} + returns a L{UNIXClientEndpoint} instance initialized with the values + from the string. """ reactor = object() client = endpoints.clientFromString( @@ -1166,6 +1583,23 @@ self.assertEqual(client._checkPID, False) + def test_unixPathPositionalArg(self): + """ + When passed a UNIX strports description specifying path as a positional + argument, L{endpoints.clientFromString} returns a L{UNIXClientEndpoint} + instance initialized with the values from the string. + """ + reactor = object() + client = endpoints.clientFromString( + reactor, + "unix:/var/foo/bar:lockfile=1:timeout=9") + self.assertIsInstance(client, endpoints.UNIXClientEndpoint) + self.assertIdentical(client._reactor, reactor) + self.assertEqual(client._path, "/var/foo/bar") + self.assertEqual(client._timeout, 9) + self.assertEqual(client._checkPID, True) + + def test_typeFromPlugin(self): """ L{endpoints.clientFromString} looks up plugins of type @@ -1238,8 +1672,32 @@ [casPath.child("thing1.pem"), casPath.child("thing2.pem")] if x.basename().lower().endswith('.pem') ] - self.assertEqual([Certificate(x) for x in certOptions.caCerts], - expectedCerts) + self.assertEqual(sorted((Certificate(x) for x in certOptions.caCerts), + key=lambda cert: cert.digest()), + sorted(expectedCerts, + key=lambda cert: cert.digest())) + + + def test_sslPositionalArgs(self): + """ + When passed an SSL strports description, L{clientFromString} returns a + L{SSL4ClientEndpoint} instance initialized with the values from the + string. + """ + reactor = object() + client = endpoints.clientFromString( + reactor, + "ssl:example.net:4321:privateKey=%s:" + "certKey=%s:bindAddress=10.0.0.3:timeout=3:caCertsDir=%s" % + (escapedPEMPathName, + escapedPEMPathName, + escapedCAsPathName)) + self.assertIsInstance(client, endpoints.SSL4ClientEndpoint) + self.assertIdentical(client._reactor, reactor) + self.assertEqual(client._host, "example.net") + self.assertEqual(client._port, 4321) + self.assertEqual(client._timeout, 3) + self.assertEqual(client._bindAddress, "10.0.0.3") def test_unreadableCertificate(self): @@ -1277,3 +1735,287 @@ self.assertEqual(certOptions.verify, False) ctx = certOptions.getContext() self.assertIsInstance(ctx, ContextType) + + + +class AdoptedStreamServerEndpointTestCase(ServerEndpointTestCaseMixin, + unittest.TestCase): + """ + Tests for adopted socket-based stream server endpoints. + """ + def _createStubbedAdoptedEndpoint(self, reactor, fileno, addressFamily): + """ + Create an L{AdoptedStreamServerEndpoint} which may safely be used with + an invalid file descriptor. This is convenient for a number of unit + tests. + """ + e = endpoints.AdoptedStreamServerEndpoint(reactor, fileno, addressFamily) + # Stub out some syscalls which would fail, given our invalid file + # descriptor. + e._close = lambda fd: None + e._setNonBlocking = lambda fd: None + return e + + + def createServerEndpoint(self, reactor, factory): + """ + Create a new L{AdoptedStreamServerEndpoint} for use by a test. + + @return: A three-tuple: + - The endpoint + - A tuple of the arguments expected to be passed to the underlying + reactor method + - An IAddress object which will match the result of + L{IListeningPort.getHost} on the port returned by the endpoint. + """ + fileno = 12 + addressFamily = AF_INET + endpoint = self._createStubbedAdoptedEndpoint( + reactor, fileno, addressFamily) + # Magic numbers come from the implementation of MemoryReactor + address = IPv4Address("TCP", "0.0.0.0", 1234) + return (endpoint, (fileno, addressFamily, factory), address) + + + def expectedServers(self, reactor): + """ + @return: The ports which were actually adopted by C{reactor} via calls + to its L{IReactorSocket.adoptStreamPort} implementation. + """ + return reactor.adoptedPorts + + + def listenArgs(self): + """ + @return: A C{dict} of additional keyword arguments to pass to the + C{createServerEndpoint}. + """ + return {} + + + def test_singleUse(self): + """ + L{AdoptedStreamServerEndpoint.listen} can only be used once. The file + descriptor given is closed after the first use, and subsequent calls to + C{listen} return a L{Deferred} that fails with L{AlreadyListened}. + """ + reactor = MemoryReactor() + endpoint = self._createStubbedAdoptedEndpoint(reactor, 13, AF_INET) + endpoint.listen(object()) + d = self.assertFailure(endpoint.listen(object()), error.AlreadyListened) + def listenFailed(ignored): + self.assertEqual(1, len(reactor.adoptedPorts)) + d.addCallback(listenFailed) + return d + + + def test_descriptionNonBlocking(self): + """ + L{AdoptedStreamServerEndpoint.listen} sets the file description given to + it to non-blocking. + """ + reactor = MemoryReactor() + endpoint = self._createStubbedAdoptedEndpoint(reactor, 13, AF_INET) + events = [] + def setNonBlocking(fileno): + events.append(("setNonBlocking", fileno)) + endpoint._setNonBlocking = setNonBlocking + + d = endpoint.listen(object()) + def listened(ignored): + self.assertEqual([("setNonBlocking", 13)], events) + d.addCallback(listened) + return d + + + def test_descriptorClosed(self): + """ + L{AdoptedStreamServerEndpoint.listen} closes its file descriptor after + adding it to the reactor with L{IReactorSocket.adoptStreamPort}. + """ + reactor = MemoryReactor() + endpoint = self._createStubbedAdoptedEndpoint(reactor, 13, AF_INET) + events = [] + def close(fileno): + events.append(("close", fileno, len(reactor.adoptedPorts))) + endpoint._close = close + + d = endpoint.listen(object()) + def listened(ignored): + self.assertEqual([("close", 13, 1)], events) + d.addCallback(listened) + return d + + + +class SystemdEndpointPluginTests(unittest.TestCase): + """ + Unit tests for the systemd stream server endpoint and endpoint string + description parser. + + @see: U{systemd} + """ + + _parserClass = endpoints._SystemdParser + + def test_pluginDiscovery(self): + """ + L{endpoints._SystemdParser} is found as a plugin for + L{interfaces.IStreamServerEndpointStringParser} interface. + """ + parsers = list(getPlugins( + interfaces.IStreamServerEndpointStringParser)) + for p in parsers: + if isinstance(p, self._parserClass): + break + else: + self.fail("Did not find systemd parser in %r" % (parsers,)) + + + def test_interface(self): + """ + L{endpoints._SystemdParser} instances provide + L{interfaces.IStreamServerEndpointStringParser}. + """ + parser = self._parserClass() + self.assertTrue(verifyObject( + interfaces.IStreamServerEndpointStringParser, parser)) + + + def _parseStreamServerTest(self, addressFamily, addressFamilyString): + """ + Helper for unit tests for L{endpoints._SystemdParser.parseStreamServer} + for different address families. + + Handling of the address family given will be verify. If there is a + problem a test-failing exception will be raised. + + @param addressFamily: An address family constant, like L{socket.AF_INET}. + + @param addressFamilyString: A string which should be recognized by the + parser as representing C{addressFamily}. + """ + reactor = object() + descriptors = [5, 6, 7, 8, 9] + index = 3 + + parser = self._parserClass() + parser._sddaemon = ListenFDs(descriptors) + + server = parser.parseStreamServer( + reactor, domain=addressFamilyString, index=str(index)) + self.assertIdentical(server.reactor, reactor) + self.assertEqual(server.addressFamily, addressFamily) + self.assertEqual(server.fileno, descriptors[index]) + + + def test_parseStreamServerINET(self): + """ + IPv4 can be specified using the string C{"INET"}. + """ + self._parseStreamServerTest(AF_INET, "INET") + + + def test_parseStreamServerINET6(self): + """ + IPv6 can be specified using the string C{"INET6"}. + """ + self._parseStreamServerTest(AF_INET6, "INET6") + + + def test_parseStreamServerUNIX(self): + """ + A UNIX domain socket can be specified using the string C{"UNIX"}. + """ + try: + from socket import AF_UNIX + except ImportError: + raise unittest.SkipTest("Platform lacks AF_UNIX support") + else: + self._parseStreamServerTest(AF_UNIX, "UNIX") + + + +class TCP6ServerEndpointPluginTests(unittest.TestCase): + """ + Unit tests for the TCP IPv6 stream server endpoint string description parser. + """ + _parserClass = endpoints._TCP6ServerParser + + def test_pluginDiscovery(self): + """ + L{endpoints._TCP6ServerParser} is found as a plugin for + L{interfaces.IStreamServerEndpointStringParser} interface. + """ + parsers = list(getPlugins( + interfaces.IStreamServerEndpointStringParser)) + for p in parsers: + if isinstance(p, self._parserClass): + break + else: + self.fail("Did not find TCP6ServerEndpoint parser in %r" % (parsers,)) + + + def test_interface(self): + """ + L{endpoints._TCP6ServerParser} instances provide + L{interfaces.IStreamServerEndpointStringParser}. + """ + parser = self._parserClass() + self.assertTrue(verifyObject( + interfaces.IStreamServerEndpointStringParser, parser)) + + + def test_stringDescription(self): + """ + L{serverFromString} returns a L{TCP6ServerEndpoint} instance with a 'tcp6' + endpoint string description. + """ + ep = endpoints.serverFromString(MemoryReactor(), + "tcp6:8080:backlog=12:interface=\:\:1") + self.assertIsInstance(ep, endpoints.TCP6ServerEndpoint) + self.assertIsInstance(ep._reactor, MemoryReactor) + self.assertEqual(ep._port, 8080) + self.assertEqual(ep._backlog, 12) + self.assertEqual(ep._interface, '::1') + + + +class StandardIOEndpointPluginTests(unittest.TestCase): + """ + Unit tests for the Standard I/O endpoint string description parser. + """ + _parserClass = endpoints._StandardIOParser + + def test_pluginDiscovery(self): + """ + L{endpoints._StandardIOParser} is found as a plugin for + L{interfaces.IStreamServerEndpointStringParser} interface. + """ + parsers = list(getPlugins( + interfaces.IStreamServerEndpointStringParser)) + for p in parsers: + if isinstance(p, self._parserClass): + break + else: + self.fail("Did not find StandardIOEndpoint parser in %r" % (parsers,)) + + + def test_interface(self): + """ + L{endpoints._StandardIOParser} instances provide + L{interfaces.IStreamServerEndpointStringParser}. + """ + parser = self._parserClass() + self.assertTrue(verifyObject( + interfaces.IStreamServerEndpointStringParser, parser)) + + + def test_stringDescription(self): + """ + L{serverFromString} returns a L{StandardIOEndpoint} instance with a 'stdio' + endpoint string description. + """ + ep = endpoints.serverFromString(MemoryReactor(), "stdio:") + self.assertIsInstance(ep, endpoints.StandardIOEndpoint) + self.assertIsInstance(ep._reactor, MemoryReactor) diff -Nru twisted-12.0.0/twisted/internet/test/test_epollreactor.py twisted-12.2.0/twisted/internet/test/test_epollreactor.py --- twisted-12.0.0/twisted/internet/test/test_epollreactor.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_epollreactor.py 2012-05-04 18:49:18.000000000 +0000 @@ -0,0 +1,246 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.internet.epollreactor}. +""" + +from twisted.trial.unittest import TestCase +try: + from twisted.internet.epollreactor import _ContinuousPolling +except ImportError: + _ContinuousPolling = None +from twisted.internet.task import Clock +from twisted.internet.error import ConnectionDone + + + +class Descriptor(object): + """ + Records reads and writes, as if it were a C{FileDescriptor}. + """ + + def __init__(self): + self.events = [] + + + def fileno(self): + return 1 + + + def doRead(self): + self.events.append("read") + + + def doWrite(self): + self.events.append("write") + + + def connectionLost(self, reason): + reason.trap(ConnectionDone) + self.events.append("lost") + + + +class ContinuousPollingTests(TestCase): + """ + L{_ContinuousPolling} can be used to read and write from C{FileDescriptor} + objects. + """ + + def test_addReader(self): + """ + Adding a reader when there was previously no reader starts up a + C{LoopingCall}. + """ + poller = _ContinuousPolling(Clock()) + self.assertEqual(poller._loop, None) + reader = object() + self.assertFalse(poller.isReading(reader)) + poller.addReader(reader) + self.assertNotEqual(poller._loop, None) + self.assertTrue(poller._loop.running) + self.assertIdentical(poller._loop.clock, poller._reactor) + self.assertTrue(poller.isReading(reader)) + + + def test_addWriter(self): + """ + Adding a writer when there was previously no writer starts up a + C{LoopingCall}. + """ + poller = _ContinuousPolling(Clock()) + self.assertEqual(poller._loop, None) + writer = object() + self.assertFalse(poller.isWriting(writer)) + poller.addWriter(writer) + self.assertNotEqual(poller._loop, None) + self.assertTrue(poller._loop.running) + self.assertIdentical(poller._loop.clock, poller._reactor) + self.assertTrue(poller.isWriting(writer)) + + + def test_removeReader(self): + """ + Removing a reader stops the C{LoopingCall}. + """ + poller = _ContinuousPolling(Clock()) + reader = object() + poller.addReader(reader) + poller.removeReader(reader) + self.assertEqual(poller._loop, None) + self.assertEqual(poller._reactor.getDelayedCalls(), []) + self.assertFalse(poller.isReading(reader)) + + + def test_removeWriter(self): + """ + Removing a writer stops the C{LoopingCall}. + """ + poller = _ContinuousPolling(Clock()) + writer = object() + poller.addWriter(writer) + poller.removeWriter(writer) + self.assertEqual(poller._loop, None) + self.assertEqual(poller._reactor.getDelayedCalls(), []) + self.assertFalse(poller.isWriting(writer)) + + + def test_removeUnknown(self): + """ + Removing unknown readers and writers silently does nothing. + """ + poller = _ContinuousPolling(Clock()) + poller.removeWriter(object()) + poller.removeReader(object()) + + + def test_multipleReadersAndWriters(self): + """ + Adding multiple readers and writers results in a single + C{LoopingCall}. + """ + poller = _ContinuousPolling(Clock()) + writer = object() + poller.addWriter(writer) + self.assertNotEqual(poller._loop, None) + poller.addWriter(object()) + self.assertNotEqual(poller._loop, None) + poller.addReader(object()) + self.assertNotEqual(poller._loop, None) + poller.addReader(object()) + poller.removeWriter(writer) + self.assertNotEqual(poller._loop, None) + self.assertTrue(poller._loop.running) + self.assertEqual(len(poller._reactor.getDelayedCalls()), 1) + + + def test_readerPolling(self): + """ + Adding a reader causes its C{doRead} to be called every 1 + milliseconds. + """ + reactor = Clock() + poller = _ContinuousPolling(reactor) + desc = Descriptor() + poller.addReader(desc) + self.assertEqual(desc.events, []) + reactor.advance(0.00001) + self.assertEqual(desc.events, ["read"]) + reactor.advance(0.00001) + self.assertEqual(desc.events, ["read", "read"]) + reactor.advance(0.00001) + self.assertEqual(desc.events, ["read", "read", "read"]) + + + def test_writerPolling(self): + """ + Adding a writer causes its C{doWrite} to be called every 1 + milliseconds. + """ + reactor = Clock() + poller = _ContinuousPolling(reactor) + desc = Descriptor() + poller.addWriter(desc) + self.assertEqual(desc.events, []) + reactor.advance(0.001) + self.assertEqual(desc.events, ["write"]) + reactor.advance(0.001) + self.assertEqual(desc.events, ["write", "write"]) + reactor.advance(0.001) + self.assertEqual(desc.events, ["write", "write", "write"]) + + + def test_connectionLostOnRead(self): + """ + If a C{doRead} returns a value indicating disconnection, + C{connectionLost} is called on it. + """ + reactor = Clock() + poller = _ContinuousPolling(reactor) + desc = Descriptor() + desc.doRead = lambda: ConnectionDone() + poller.addReader(desc) + self.assertEqual(desc.events, []) + reactor.advance(0.001) + self.assertEqual(desc.events, ["lost"]) + + + def test_connectionLostOnWrite(self): + """ + If a C{doWrite} returns a value indicating disconnection, + C{connectionLost} is called on it. + """ + reactor = Clock() + poller = _ContinuousPolling(reactor) + desc = Descriptor() + desc.doWrite = lambda: ConnectionDone() + poller.addWriter(desc) + self.assertEqual(desc.events, []) + reactor.advance(0.001) + self.assertEqual(desc.events, ["lost"]) + + + def test_removeAll(self): + """ + L{_ContinuousPolling.removeAll} removes all descriptors and returns + the readers and writers. + """ + poller = _ContinuousPolling(Clock()) + reader = object() + writer = object() + both = object() + poller.addReader(reader) + poller.addReader(both) + poller.addWriter(writer) + poller.addWriter(both) + removed = poller.removeAll() + self.assertEqual(poller.getReaders(), []) + self.assertEqual(poller.getWriters(), []) + self.assertEqual(len(removed), 3) + self.assertEqual(set(removed), set([reader, writer, both])) + + + def test_getReaders(self): + """ + L{_ContinuousPolling.getReaders} returns a list of the read + descriptors. + """ + poller = _ContinuousPolling(Clock()) + reader = object() + poller.addReader(reader) + self.assertIn(reader, poller.getReaders()) + + + def test_getWriters(self): + """ + L{_ContinuousPolling.getWriters} returns a list of the write + descriptors. + """ + poller = _ContinuousPolling(Clock()) + writer = object() + poller.addWriter(writer) + self.assertIn(writer, poller.getWriters()) + + if _ContinuousPolling is None: + skip = "epoll not supported in this environment." diff -Nru twisted-12.0.0/twisted/internet/test/test_fdset.py twisted-12.2.0/twisted/internet/test/test_fdset.py --- twisted-12.0.0/twisted/internet/test/test_fdset.py 2011-11-02 13:15:43.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_fdset.py 2012-01-23 22:55:41.000000000 +0000 @@ -286,7 +286,7 @@ reactor = self.buildReactor() name = reactor.__class__.__name__ - if name in ('EPollReactor', 'CFReactor'): + if name in ('EPollReactor', 'KQueueReactor', 'CFReactor'): # Closing a file descriptor immediately removes it from the epoll # set without generating a notification. That means epollreactor # will not call any methods on Victim after the close, so there's diff -Nru twisted-12.0.0/twisted/internet/test/test_filedescriptor.py twisted-12.2.0/twisted/internet/test/test_filedescriptor.py --- twisted-12.0.0/twisted/internet/test/test_filedescriptor.py 2011-10-28 15:35:02.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_filedescriptor.py 2012-03-15 20:18:28.000000000 +0000 @@ -5,14 +5,17 @@ Whitebox tests for L{twisted.internet.abstract.FileDescriptor}. """ +from zope.interface.verify import verifyClass + from twisted.internet.abstract import FileDescriptor +from twisted.internet.interfaces import IPushProducer from twisted.trial.unittest import TestCase -class FileDescriptorWriteSequenceTests(TestCase): +class FileDescriptorTests(TestCase): """ - Tests for L{FileDescriptor.writeSequence}. + Tests for L{FileDescriptor}. """ def test_writeWithUnicodeRaisesException(self): """ @@ -29,3 +32,10 @@ fileDescriptor = FileDescriptor() self.assertRaises( TypeError, fileDescriptor.writeSequence, ['foo', u'bar', 'baz']) + + + def test_implementInterfaceIPushProducer(self): + """ + L{FileDescriptor} should implement L{IPushProducer}. + """ + self.assertTrue(verifyClass(IPushProducer, FileDescriptor)) diff -Nru twisted-12.0.0/twisted/internet/test/test_glibbase.py twisted-12.2.0/twisted/internet/test/test_glibbase.py --- twisted-12.0.0/twisted/internet/test/test_glibbase.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_glibbase.py 2012-03-13 14:46:45.000000000 +0000 @@ -0,0 +1,66 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for twisted.internet.glibbase. +""" + +import sys +from twisted.trial.unittest import TestCase +from twisted.internet._glibbase import ensureNotImported + + + +class EnsureNotImportedTests(TestCase): + """ + L{ensureNotImported} protects against unwanted past and future imports. + """ + + def test_ensureWhenNotImported(self): + """ + If the specified modules have never been imported, and import + prevention is requested, L{ensureNotImported} makes sure they will not + be imported in the future. + """ + modules = {} + self.patch(sys, "modules", modules) + ensureNotImported(["m1", "m2"], "A message.", + preventImports=["m1", "m2", "m3"]) + self.assertEquals(modules, {"m1": None, "m2": None, "m3": None}) + + + def test_ensureWhenNotImportedDontPrevent(self): + """ + If the specified modules have never been imported, and import + prevention is not requested, L{ensureNotImported} has no effect. + """ + modules = {} + self.patch(sys, "modules", modules) + ensureNotImported(["m1", "m2"], "A message.") + self.assertEquals(modules, {}) + + + def test_ensureWhenFailedToImport(self): + """ + If the specified modules have been set to C{None} in C{sys.modules}, + L{ensureNotImported} does not complain. + """ + modules = {"m2": None} + self.patch(sys, "modules", modules) + ensureNotImported(["m1", "m2"], "A message.", preventImports=["m1", "m2"]) + self.assertEquals(modules, {"m1": None, "m2": None}) + + + def test_ensureFailsWhenImported(self): + """ + If one of the specified modules has been previously imported, + L{ensureNotImported} raises an exception. + """ + module = object() + modules = {"m2": module} + self.patch(sys, "modules", modules) + e = self.assertRaises(ImportError, ensureNotImported, + ["m1", "m2"], "A message.", + preventImports=["m1", "m2"]) + self.assertEquals(modules, {"m2": module}) + self.assertEquals(e.args, ("A message.",)) diff -Nru twisted-12.0.0/twisted/internet/test/test_gtk3reactor.py twisted-12.2.0/twisted/internet/test/test_gtk3reactor.py --- twisted-12.0.0/twisted/internet/test/test_gtk3reactor.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_gtk3reactor.py 2012-05-12 22:44:21.000000000 +0000 @@ -0,0 +1,152 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +GI/GTK3 reactor tests. +""" + +try: + from twisted.internet import gireactor, gtk3reactor + from gi.repository import Gtk, Gio +except ImportError: + gireactor = None + +from twisted.internet.error import ReactorAlreadyRunning +from twisted.trial.unittest import TestCase, SkipTest +from twisted.internet.test.reactormixins import ReactorBuilder + + + +class GtkApplicationRegistration(ReactorBuilder, TestCase): + """ + GtkApplication and GApplication are supported by + L{twisted.internet.gtk3reactor} and L{twisted.internet.gireactor}. + + We inherit from L{ReactorBuilder} in order to use some of its + reactor-running infrastructure, but don't need its test-creation + functionality. + """ + if gireactor is None: + skip = "gtk3/gi not importable" + + + def runReactor(self, app, reactor): + """ + Register the app, run the reactor, make sure app was activated, and + that reactor was running, and that reactor can be stopped. + """ + if not hasattr(app, "quit"): + raise SkipTest("Version of PyGObject is too old.") + + result = [] + def stop(): + result.append("stopped") + reactor.stop() + def activate(widget): + result.append("activated") + reactor.callLater(0, stop) + app.connect('activate', activate) + + # We want reactor.stop() to *always* stop the event loop, even if + # someone has called hold() on the application and never done the + # corresponding release() -- for more details see + # http://developer.gnome.org/gio/unstable/GApplication.html. + app.hold() + + reactor.registerGApplication(app) + ReactorBuilder.runReactor(self, reactor) + self.assertEqual(result, ["activated", "stopped"]) + + + def test_gApplicationActivate(self): + """ + L{Gio.Application} instances can be registered with a gireactor. + """ + reactor = gireactor.GIReactor(useGtk=False) + self.addCleanup(self.unbuildReactor, reactor) + app = Gio.Application( + application_id='com.twistedmatrix.trial.gireactor', + flags=Gio.ApplicationFlags.FLAGS_NONE) + + self.runReactor(app, reactor) + + + def test_gtkApplicationActivate(self): + """ + L{Gtk.Application} instances can be registered with a gtk3reactor. + """ + reactor = gtk3reactor.Gtk3Reactor() + self.addCleanup(self.unbuildReactor, reactor) + app = Gtk.Application( + application_id='com.twistedmatrix.trial.gtk3reactor', + flags=Gio.ApplicationFlags.FLAGS_NONE) + + self.runReactor(app, reactor) + + + def test_portable(self): + """ + L{gireactor.PortableGIReactor} doesn't support application + registration at this time. + """ + reactor = gireactor.PortableGIReactor() + self.addCleanup(self.unbuildReactor, reactor) + app = Gio.Application( + application_id='com.twistedmatrix.trial.gireactor', + flags=Gio.ApplicationFlags.FLAGS_NONE) + self.assertRaises(NotImplementedError, + reactor.registerGApplication, app) + + + def test_noQuit(self): + """ + Older versions of PyGObject lack C{Application.quit}, and so won't + allow registration. + """ + reactor = gireactor.GIReactor(useGtk=False) + self.addCleanup(self.unbuildReactor, reactor) + # An app with no "quit" method: + app = object() + exc = self.assertRaises(RuntimeError, reactor.registerGApplication, app) + self.assertTrue(exc.args[0].startswith( + "Application registration is not")) + + + def test_cantRegisterAfterRun(self): + """ + It is not possible to register a C{Application} after the reactor has + already started. + """ + reactor = gireactor.GIReactor(useGtk=False) + self.addCleanup(self.unbuildReactor, reactor) + app = Gio.Application( + application_id='com.twistedmatrix.trial.gireactor', + flags=Gio.ApplicationFlags.FLAGS_NONE) + + def tryRegister(): + exc = self.assertRaises(ReactorAlreadyRunning, + reactor.registerGApplication, app) + self.assertEqual(exc.args[0], + "Can't register application after reactor was started.") + reactor.stop() + reactor.callLater(0, tryRegister) + ReactorBuilder.runReactor(self, reactor) + + + def test_cantRegisterTwice(self): + """ + It is not possible to register more than one C{Application}. + """ + reactor = gireactor.GIReactor(useGtk=False) + self.addCleanup(self.unbuildReactor, reactor) + app = Gio.Application( + application_id='com.twistedmatrix.trial.gireactor', + flags=Gio.ApplicationFlags.FLAGS_NONE) + reactor.registerGApplication(app) + app2 = Gio.Application( + application_id='com.twistedmatrix.trial.gireactor2', + flags=Gio.ApplicationFlags.FLAGS_NONE) + exc = self.assertRaises(RuntimeError, + reactor.registerGApplication, app2) + self.assertEqual(exc.args[0], + "Can't register more than one application instance.") diff -Nru twisted-12.0.0/twisted/internet/test/test_iocp.py twisted-12.2.0/twisted/internet/test/test_iocp.py --- twisted-12.0.0/twisted/internet/test/test_iocp.py 2011-11-02 00:53:45.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_iocp.py 2012-03-15 20:18:28.000000000 +0000 @@ -14,12 +14,14 @@ from twisted.trial import unittest from twisted.python.log import msg +from twisted.internet.interfaces import IPushProducer try: from twisted.internet.iocpreactor import iocpsupport as _iocp, tcp, udp from twisted.internet.iocpreactor.reactor import IOCPReactor, EVENTS_PER_LOOP, KEY_NORMAL from twisted.internet.iocpreactor.interfaces import IReadWriteHandle from twisted.internet.iocpreactor.const import SO_UPDATE_ACCEPT_CONTEXT + from twisted.internet.iocpreactor.abstract import FileHandle except ImportError: skip = 'This test only applies to IOCPReactor' @@ -113,8 +115,15 @@ """ Verify that IOCP socket-representing classes implement IReadWriteHandle """ - verifyClass(IReadWriteHandle, tcp.Connection) - verifyClass(IReadWriteHandle, udp.Port) + self.assertTrue(verifyClass(IReadWriteHandle, tcp.Connection)) + self.assertTrue(verifyClass(IReadWriteHandle, udp.Port)) + + + def test_fileHandleInterfaces(self): + """ + Verify that L{Filehandle} implements L{IPushProducer}. + """ + self.assertTrue(verifyClass(IPushProducer, FileHandle)) def test_maxEventsPerIteration(self): diff -Nru twisted-12.0.0/twisted/internet/test/test_newtls.py twisted-12.2.0/twisted/internet/test/test_newtls.py --- twisted-12.0.0/twisted/internet/test/test_newtls.py 2011-12-08 19:58:50.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_newtls.py 2012-04-12 03:14:29.000000000 +0000 @@ -6,10 +6,12 @@ """ from twisted.trial import unittest -from twisted.internet.test.reactormixins import ReactorBuilder -from twisted.internet import protocol -from twisted.internet.defer import Deferred -from twisted.internet.test.test_tls import ContextGeneratingMixin, TLSMixin +from twisted.internet.test.reactormixins import ReactorBuilder, runProtocolsWithReactor +from twisted.internet.test.reactormixins import ConnectableProtocol +from twisted.internet.test.test_tls import SSLCreator, TLSMixin +from twisted.internet.test.test_tls import StartTLSClientCreator +from twisted.internet.test.test_tls import ContextGeneratingMixin +from twisted.internet.test.test_tcp import TCPCreator try: from twisted.protocols import tls from twisted.internet import _newtls @@ -69,16 +71,15 @@ -class ProducerProtocol(protocol.Protocol): +class ProducerProtocol(ConnectableProtocol): """ Register a producer, unregister it, and verify the producer hooks up to innards of C{TLSMemoryBIOProtocol}. """ - def __init__(self, producer, result, doneDeferred): + def __init__(self, producer, result): self.producer = producer self.result = result - self.done = doneDeferred def connectionMade(self): @@ -97,11 +98,6 @@ self.transport.loseConnection() - def connectionLost(self, reason): - self.done.callback(None) - del self.done - - class ProducerTestsMixin(ReactorBuilder, TLSMixin, ContextGeneratingMixin): """ @@ -118,28 +114,11 @@ C{TLSMemoryBIOProtocol}, not the underlying transport directly. """ result = [] - done = Deferred() producer = FakeProducer() - serverFactory = protocol.ServerFactory - serverFactory.protocol = protocol.Protocol - reactor = self.buildReactor() - serverPort = reactor.listenSSL(0, protocol.ServerFactory(), - self.getServerContext(), - interface="127.0.0.1") - self.addCleanup(serverPort.stopListening) - - factory = protocol.ClientFactory() - factory.buildProtocol = lambda addr: ProducerProtocol(producer, - result, done) - reactor.connectSSL("127.0.0.1", serverPort.getHost().port, factory, - self.getClientContext()) - - def gotResult(_): - reactor.stop() - done.addCallback(gotResult) - self.runReactor(reactor) - + runProtocolsWithReactor(self, ConnectableProtocol(), + ProducerProtocol(producer, result), + SSLCreator()) self.assertEqual(result, [producer, None]) @@ -150,38 +129,11 @@ the underlying transport directly. """ result = [] - done = Deferred() - clientContext = self.getClientContext() - serverContext = self.getServerContext() - producer = FakeProducer() - class StartTLSProtocol(protocol.Protocol): - def connectionMade(self): - self.transport.startTLS(serverContext) - - serverFactory = protocol.ServerFactory - serverFactory.protocol = StartTLSProtocol - reactor = self.buildReactor() - serverPort = reactor.listenTCP(0, protocol.ServerFactory(), - interface="127.0.0.1") - self.addCleanup(serverPort.stopListening) - - class TLSProducerProtocol(ProducerProtocol): - def connectionMade(self): - self.transport.startTLS(clientContext) - ProducerProtocol.connectionMade(self) - - factory = protocol.ClientFactory() - factory.buildProtocol = lambda addr: TLSProducerProtocol(producer, - result, done) - reactor.connectTCP("127.0.0.1", serverPort.getHost().port, factory) - - def gotResult(_): - reactor.stop() - done.addCallback(gotResult) - self.runReactor(reactor) - + runProtocolsWithReactor(self, ConnectableProtocol(), + ProducerProtocol(producer, result), + StartTLSClientCreator()) self.assertEqual(result, [producer, None]) @@ -190,15 +142,12 @@ When a producer is registered, and then startTLS is called, the producer is re-registered with the C{TLSMemoryBIOProtocol}. """ - result = [] - done = Deferred() clientContext = self.getClientContext() serverContext = self.getServerContext() - + result = [] producer = FakeProducer() - reactor = self.buildReactor() - class RegisterTLSProtocol(protocol.Protocol): + class RegisterTLSProtocol(ConnectableProtocol): def connectionMade(self): self.transport.registerProducer(producer, streaming) self.transport.startTLS(serverContext) @@ -216,24 +165,12 @@ self.transport.unregisterProducer() self.transport.loseConnection() - def connectionLost(self, reason): - reactor.stop() - - serverFactory = protocol.ServerFactory - serverFactory.protocol = RegisterTLSProtocol - serverPort = reactor.listenTCP(0, protocol.ServerFactory(), - interface="127.0.0.1") - self.addCleanup(serverPort.stopListening) - - class StartTLSProtocol(protocol.Protocol): + class StartTLSProtocol(ConnectableProtocol): def connectionMade(self): self.transport.startTLS(clientContext) - factory = protocol.ClientFactory() - factory.protocol = StartTLSProtocol - reactor.connectTCP("127.0.0.1", serverPort.getHost().port, factory) - self.runReactor(reactor, timeout=2) - + runProtocolsWithReactor(self, RegisterTLSProtocol(), + StartTLSProtocol(), TCPCreator()) self.assertEqual(result, [producer, producer]) diff -Nru twisted-12.0.0/twisted/internet/test/test_pollingfile.py twisted-12.2.0/twisted/internet/test/test_pollingfile.py --- twisted-12.0.0/twisted/internet/test/test_pollingfile.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_pollingfile.py 2012-04-14 00:21:00.000000000 +0000 @@ -20,20 +20,27 @@ Tests for L{_pollingfile._PollableWritePipe}. """ - def test_checkWorkUnicode(self): + def test_writeUnicode(self): """ - When one tries to pass unicode to L{_pollingfile._PollableWritePipe}, a - C{TypeError} is raised instead of passing the data to C{WriteFile} - call which is going to mangle it. + L{_pollingfile._PollableWritePipe.write} raises a C{TypeError} if an + attempt is made to append unicode data to the output buffer. """ p = _pollingfile._PollableWritePipe(1, lambda: None) - p.write("test") - p.checkWork() + self.assertRaises(TypeError, p.write, u"test") + + + def test_writeSequenceUnicode(self): + """ + L{_pollingfile._PollableWritePipe.writeSequence} raises a C{TypeError} + if unicode data is part of the data sequence to be appended to the + output buffer. + """ + p = _pollingfile._PollableWritePipe(1, lambda: None) + self.assertRaises(TypeError, p.writeSequence, [u"test"]) + self.assertRaises(TypeError, p.writeSequence, (u"test", )) - p.write(u"test") - self.assertRaises(TypeError, p.checkWork) if _pollingfile is None: - TestPollableWritePipe.skip = "_pollingfile is only avalable under Windows." + TestPollableWritePipe.skip = "Test will run only on Windows." diff -Nru twisted-12.0.0/twisted/internet/test/test_posixbase.py twisted-12.2.0/twisted/internet/test/test_posixbase.py --- twisted-12.0.0/twisted/internet/test/test_posixbase.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_posixbase.py 2012-06-07 14:09:07.000000000 +0000 @@ -188,7 +188,7 @@ """ port = Port(12345, ServerFactory()) port.connected = True - port.connectionLost = lambda reason: 1 / 0 + port.connectionLost = lambda reason: 1 // 0 return self.assertFailure(port.stopListening(), ZeroDivisionError) diff -Nru twisted-12.0.0/twisted/internet/test/test_process.py twisted-12.2.0/twisted/internet/test/test_process.py --- twisted-12.0.0/twisted/internet/test/test_process.py 2011-10-02 02:01:47.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_process.py 2012-06-17 15:15:44.000000000 +0000 @@ -384,6 +384,33 @@ self.runReactor(reactor) + def test_timelyProcessExited(self): + """ + If a spawned process exits, C{processExited} will be called in a + timely manner. + """ + reactor = self.buildReactor() + + class ExitingProtocol(ProcessProtocol): + exited = False + + def processExited(protoSelf, reason): + protoSelf.exited = True + reactor.stop() + self.assertEqual(reason.value.exitCode, 0) + + protocol = ExitingProtocol() + reactor.callWhenRunning( + reactor.spawnProcess, protocol, sys.executable, + [sys.executable, "-c", "raise SystemExit(0)"], + usePTY=self.usePTY) + + # This will timeout if processExited isn't called: + self.runReactor(reactor, timeout=30) + self.assertEqual(protocol.exited, True) + + + class ProcessTestsBuilder(ProcessTestsBuilderBase): """ Builder defining tests relating to L{IReactorProcess} for child processes diff -Nru twisted-12.0.0/twisted/internet/test/test_socket.py twisted-12.2.0/twisted/internet/test/test_socket.py --- twisted-12.0.0/twisted/internet/test/test_socket.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_socket.py 2012-07-28 14:29:16.000000000 +0000 @@ -0,0 +1,128 @@ + +import errno, socket + +from twisted.python.log import err +from twisted.internet.interfaces import IReactorSocket +from twisted.internet.error import UnsupportedAddressFamily +from twisted.internet.protocol import ServerFactory +from twisted.internet.test.reactormixins import ( + ReactorBuilder, needsRunningReactor) + + +class AdoptStreamPortErrorsTestsBuilder(ReactorBuilder): + """ + Builder for testing L{IReactorSocket.adoptStreamPort} implementations. + + Generally only tests for failure cases are found here. Success cases for + this interface are tested elsewhere. For example, the success case for + I{AF_INET} is in L{twisted.internet.test.test_tcp}, since that case should + behave exactly the same as L{IReactorTCP.listenTCP}. + """ + requiredInterfaces = [IReactorSocket] + + def test_invalidDescriptor(self): + """ + An implementation of L{IReactorSocket.adoptStreamPort} raises + L{socket.error} if passed an integer which is not associated with a + socket. + """ + reactor = self.buildReactor() + + probe = socket.socket() + fileno = probe.fileno() + probe.close() + + exc = self.assertRaises( + socket.error, + reactor.adoptStreamPort, fileno, socket.AF_INET, ServerFactory()) + self.assertEqual(exc.args[0], errno.EBADF) + + + def test_invalidAddressFamily(self): + """ + An implementation of L{IReactorSocket.adoptStreamPort} raises + L{UnsupportedAddressFamily} if passed an address family it does not + support. + """ + reactor = self.buildReactor() + + port = socket.socket() + port.listen(1) + self.addCleanup(port.close) + + arbitrary = 2 ** 16 + 7 + + self.assertRaises( + UnsupportedAddressFamily, + reactor.adoptStreamPort, port.fileno(), arbitrary, ServerFactory()) + + + def test_stopOnlyCloses(self): + """ + When the L{IListeningPort} returned by L{IReactorSocket.adoptStreamPort} + is stopped using C{stopListening}, the underlying socket is closed but + not shutdown. This allows another process which still has a reference + to it to continue accepting connections over it. + """ + reactor = self.buildReactor() + + portSocket = socket.socket() + self.addCleanup(portSocket.close) + + portSocket.listen(1) + portSocket.setblocking(False) + + # The file descriptor is duplicated by adoptStreamPort + port = reactor.adoptStreamPort( + portSocket.fileno(), portSocket.family, ServerFactory()) + d = port.stopListening() + def stopped(ignored): + # Should still be possible to accept a connection on portSocket. If + # it was shutdown, the exception would be EINVAL instead. + exc = self.assertRaises(socket.error, portSocket.accept) + self.assertEqual(exc.args[0], errno.EAGAIN) + d.addCallback(stopped) + d.addErrback(err, "Failed to accept on original port.") + + needsRunningReactor( + reactor, + lambda: d.addCallback(lambda ignored: reactor.stop())) + + reactor.run() + + + +class AdoptStreamConnectionErrorsTestsBuilder(ReactorBuilder): + """ + Builder for testing L{IReactorSocket.adoptStreamConnection} + implementations. + + Generally only tests for failure cases are found here. Success cases for + this interface are tested elsewhere. For example, the success case for + I{AF_INET} is in L{twisted.internet.test.test_tcp}, since that case should + behave exactly the same as L{IReactorTCP.listenTCP}. + """ + requiredInterfaces = [IReactorSocket] + + def test_invalidAddressFamily(self): + """ + An implementation of L{IReactorSocket.adoptStreamConnection} raises + L{UnsupportedAddressFamily} if passed an address family it does not + support. + """ + reactor = self.buildReactor() + + connection = socket.socket() + self.addCleanup(connection.close) + + arbitrary = 2 ** 16 + 7 + + self.assertRaises( + UnsupportedAddressFamily, + reactor.adoptStreamConnection, connection.fileno(), arbitrary, + ServerFactory()) + + + +globals().update(AdoptStreamPortErrorsTestsBuilder.makeTestCaseClasses()) +globals().update(AdoptStreamConnectionErrorsTestsBuilder.makeTestCaseClasses()) diff -Nru twisted-12.0.0/twisted/internet/test/test_stdio.py twisted-12.2.0/twisted/internet/test/test_stdio.py --- twisted-12.0.0/twisted/internet/test/test_stdio.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_stdio.py 2012-05-04 18:49:18.000000000 +0000 @@ -0,0 +1,195 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.internet.stdio}. +""" + +from twisted.python.runtime import platform +from twisted.internet.test.reactormixins import ReactorBuilder +from twisted.internet.protocol import Protocol +if not platform.isWindows(): + from twisted.internet._posixstdio import StandardIO + + + +class StdioFilesTests(ReactorBuilder): + """ + L{StandardIO} supports reading and writing to filesystem files. + """ + + def setUp(self): + path = self.mktemp() + file(path, "w").close() + self.extraFile = file(path, "r+") + + + def test_addReader(self): + """ + Adding a filesystem file reader to a reactor will make sure it is + polled. + """ + reactor = self.buildReactor() + + class DataProtocol(Protocol): + data = "" + def dataReceived(self, data): + self.data += data + # It'd be better to stop reactor on connectionLost, but that + # fails on FreeBSD, probably due to + # http://bugs.python.org/issue9591: + if self.data == "hello!": + reactor.stop() + + path = self.mktemp() + f = file(path, "w") + f.write("hello!") + f.close() + f = file(path, "r") + + # Read bytes from a file, deliver them to a protocol instance: + protocol = DataProtocol() + StandardIO(protocol, stdin=f.fileno(), + stdout=self.extraFile.fileno(), + reactor=reactor) + + self.runReactor(reactor) + self.assertEqual(protocol.data, "hello!") + + + def test_addWriter(self): + """ + Adding a filesystem file writer to a reactor will make sure it is + polled. + """ + reactor = self.buildReactor() + + class DisconnectProtocol(Protocol): + def connectionLost(self, reason): + reactor.stop() + + path = self.mktemp() + f = file(path, "w") + + # Write bytes to a transport, hopefully have them written to a file: + protocol = DisconnectProtocol() + StandardIO(protocol, stdout=f.fileno(), + stdin=self.extraFile.fileno(), reactor=reactor) + protocol.transport.write("hello") + protocol.transport.write(", world") + protocol.transport.loseConnection() + + self.runReactor(reactor) + f.close() + f = file(path, "r") + self.assertEqual(f.read(), "hello, world") + f.close() + + + def test_removeReader(self): + """ + Removing a filesystem file reader from a reactor will make sure it is + no longer polled. + """ + reactor = self.buildReactor() + self.addCleanup(self.unbuildReactor, reactor) + + path = self.mktemp() + file(path, "w").close() + # Cleanup might fail if file is GCed too soon: + self.f = f = file(path, "r") + + # Have the reader added: + stdio = StandardIO(Protocol(), stdin=f.fileno(), + stdout=self.extraFile.fileno(), + reactor=reactor) + self.assertIn(stdio._reader, reactor.getReaders()) + stdio._reader.stopReading() + self.assertNotIn(stdio._reader, reactor.getReaders()) + + + def test_removeWriter(self): + """ + Removing a filesystem file writer from a reactor will make sure it is + no longer polled. + """ + reactor = self.buildReactor() + self.addCleanup(self.unbuildReactor, reactor) + + # Cleanup might fail if file is GCed too soon: + self.f = f = file(self.mktemp(), "w") + + # Have the reader added: + protocol = Protocol() + stdio = StandardIO(protocol, stdout=f.fileno(), + stdin=self.extraFile.fileno(), + reactor=reactor) + protocol.transport.write("hello") + self.assertIn(stdio._writer, reactor.getWriters()) + stdio._writer.stopWriting() + self.assertNotIn(stdio._writer, reactor.getWriters()) + + + def test_removeAll(self): + """ + Calling C{removeAll} on a reactor includes descriptors that are + filesystem files. + """ + reactor = self.buildReactor() + self.addCleanup(self.unbuildReactor, reactor) + + path = self.mktemp() + file(path, "w").close() + # Cleanup might fail if file is GCed too soon: + self.f = f = file(path, "r") + + # Have the reader added: + stdio = StandardIO(Protocol(), stdin=f.fileno(), + stdout=self.extraFile.fileno(), reactor=reactor) + # And then removed: + removed = reactor.removeAll() + self.assertIn(stdio._reader, removed) + self.assertNotIn(stdio._reader, reactor.getReaders()) + + + def test_getReaders(self): + """ + C{reactor.getReaders} includes descriptors that are filesystem files. + """ + reactor = self.buildReactor() + self.addCleanup(self.unbuildReactor, reactor) + + path = self.mktemp() + file(path, "w").close() + # Cleanup might fail if file is GCed too soon: + self.f = f = file(path, "r") + + # Have the reader added: + stdio = StandardIO(Protocol(), stdin=f.fileno(), + stdout=self.extraFile.fileno(), reactor=reactor) + self.assertIn(stdio._reader, reactor.getReaders()) + + + def test_getWriters(self): + """ + C{reactor.getWriters} includes descriptors that are filesystem files. + """ + reactor = self.buildReactor() + self.addCleanup(self.unbuildReactor, reactor) + + # Cleanup might fail if file is GCed too soon: + self.f = f = file(self.mktemp(), "w") + + # Have the reader added: + stdio = StandardIO(Protocol(), stdout=f.fileno(), + stdin=self.extraFile.fileno(), reactor=reactor) + self.assertNotIn(stdio._writer, reactor.getWriters()) + stdio._writer.startWriting() + self.assertIn(stdio._writer, reactor.getWriters()) + + if platform.isWindows(): + skip = ("StandardIO does not accept stdout as an argument to Windows. " + "Testing redirection to a file is therefore harder.") + + +globals().update(StdioFilesTests.makeTestCaseClasses()) diff -Nru twisted-12.0.0/twisted/internet/test/test_tcp.py twisted-12.2.0/twisted/internet/test/test_tcp.py --- twisted-12.0.0/twisted/internet/test/test_tcp.py 2012-01-22 00:48:15.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_tcp.py 2012-07-28 14:29:16.000000000 +0000 @@ -2,7 +2,8 @@ # See LICENSE for details. """ -Tests for implementations of L{IReactorTCP}. +Tests for implementations of L{IReactorTCP} and the TCP parts of +L{IReactorSocket}. """ __metaclass__ = type @@ -10,39 +11,43 @@ import socket, errno from zope.interface import implements -from zope.interface.verify import verifyObject from twisted.python.runtime import platform from twisted.python.failure import Failure from twisted.python import log from twisted.trial.unittest import SkipTest, TestCase -from twisted.internet.test.reactormixins import ReactorBuilder -from twisted.internet.error import DNSLookupError, ConnectionLost -from twisted.internet.error import ConnectionDone, ConnectionAborted +from twisted.internet.test.reactormixins import ReactorBuilder, EndpointCreator +from twisted.internet.test.reactormixins import ConnectableProtocol +from twisted.internet.test.reactormixins import runProtocolsWithReactor +from twisted.internet.error import ( + ConnectionLost, UserError, ConnectionRefusedError, ConnectionDone, + ConnectionAborted) from twisted.internet.interfaces import ( - ILoggingContext, IResolverSimple, IConnector, IReactorFDSet, - ITLSTransport) + ILoggingContext, IConnector, IReactorFDSet, IReactorSocket, IReactorTCP) from twisted.internet.address import IPv4Address, IPv6Address from twisted.internet.defer import ( - Deferred, DeferredList, succeed, fail, maybeDeferred, gatherResults) -from twisted.internet.endpoints import TCP4ServerEndpoint, TCP4ClientEndpoint + Deferred, DeferredList, maybeDeferred, gatherResults) +from twisted.internet.endpoints import ( + TCP4ServerEndpoint, TCP4ClientEndpoint) from twisted.internet.protocol import ServerFactory, ClientFactory, Protocol from twisted.internet.interfaces import ( IPushProducer, IPullProducer, IHalfCloseableProtocol) -from twisted.internet.protocol import ClientCreator -from twisted.internet.tcp import Connection, Server +from twisted.internet.tcp import Connection, Server, _resolveIPv6 from twisted.internet.test.connectionmixins import ( - LogObserverMixin, ConnectionTestsMixin, serverFactoryFor) + LogObserverMixin, ConnectionTestsMixin, TCPClientTestsMixin, findFreePort) from twisted.internet.test.test_core import ObjectModelIntegrationMixin from twisted.test.test_tcp import MyClientFactory, MyServerFactory -from twisted.test.test_tcp import ClosingProtocol +from twisted.test.test_tcp import ClosingFactory, ClientStartStopFactory try: - from twisted.internet.ssl import ClientContextFactory + from OpenSSL import SSL except ImportError: - ClientContextFactory = None + useSSL = False +else: + from twisted.internet.ssl import ClientContextFactory + useSSL = True try: socket.socket(socket.AF_INET6, socket.SOCK_STREAM).close() @@ -65,6 +70,7 @@ getLinkLocalIPv6Addresses = _posixifaces.posixGetLinkLocalIPv6Addresses + def getLinkLocalIPv6Address(): """ Find and return a configured link local IPv6 address including a scope @@ -83,31 +89,8 @@ -def findFreePort(interface='127.0.0.1', family=socket.AF_INET, - type=socket.SOCK_STREAM): - """ - Ask the platform to allocate a free port on the specified interface, - then release the socket and return the address which was allocated. - - @param interface: The local address to try to bind the port on. - @type interface: C{str} - - @param type: The socket type which will use the resulting port. - - @return: A two-tuple of address and port, like that returned by - L{socket.getsockname}. - """ - probe = socket.socket(family, type) - try: - probe.bind((interface, 0)) - return probe.getsockname() - finally: - probe.close() - - - def connect(client, (host, port)): - if '%' in host: + if '%' in host or ':' in host: address = socket.getaddrinfo(host, port)[0][4] else: address = (host, port) @@ -115,82 +98,6 @@ -class BrokenContextFactory(object): - """ - A context factory with a broken C{getContext} method, for exercising the - error handling for such a case. - """ - message = "Some path was wrong maybe" - - def getContext(self): - raise ValueError(self.message) - - - -class Stop(ClientFactory): - """ - A client factory which stops a reactor when a connection attempt fails. - """ - def __init__(self, reactor): - self.reactor = reactor - - - def clientConnectionFailed(self, connector, reason): - self.reactor.stop() - - - -class FakeResolver: - """ - A resolver implementation based on a C{dict} mapping names to addresses. - """ - implements(IResolverSimple) - - def __init__(self, names): - self.names = names - - - def getHostByName(self, name, timeout): - try: - return succeed(self.names[name]) - except KeyError: - return fail(DNSLookupError("FakeResolver couldn't find " + name)) - - - -class _SimplePullProducer(object): - """ - A pull producer which writes one byte whenever it is resumed. For use by - L{test_unregisterProducerAfterDisconnect}. - """ - def __init__(self, consumer): - self.consumer = consumer - - - def stopProducing(self): - pass - - - def resumeProducing(self): - log.msg("Producer.resumeProducing") - self.consumer.write('x') - - - -def _getWriters(reactor): - """ - Like L{IReactorFDSet.getWriters}, but with support for IOCP reactor as well. - """ - if IReactorFDSet.providedBy(reactor): - return reactor.getWriters() - elif 'IOCP' in reactor.__class__.__name__: - return reactor.handles - else: - # Cannot tell what is going on. - raise Exception("Cannot find writers on %r" % (reactor,)) - - - class FakeSocket(object): """ A fake for L{socket.socket} objects. @@ -408,267 +315,258 @@ conn._tlsClientDefault = True conn.startTLS(ClientContextFactory(), True) self.assertTrue(conn.TLS) - if ClientContextFactory is None: + if not useSSL: test_tlsAfterStartTLS.skip = "No SSL support available" -class TCPClientTestsBuilder(ReactorBuilder, ConnectionTestsMixin): + +class TCPCreator(EndpointCreator): """ - Builder defining tests relating to L{IReactorTCP.connectTCP}. + Create IPv4 TCP endpoints for L{runProtocolsWithReactor}-based tests. """ - def serverEndpoint(self, reactor): + + interface = "127.0.0.1" + + def server(self, reactor): """ - Create a L{TCP4ServerEndpoint} listening on localhost on a - TCP/IP-selected port. + Create a server-side TCP endpoint. """ - return TCP4ServerEndpoint(reactor, 0, interface='127.0.0.1') + return TCP4ServerEndpoint(reactor, 0, interface=self.interface) - def clientEndpoint(self, reactor, serverAddress): + def client(self, reactor, serverAddress): """ - Create a L{TCP4ClientEndpoint} which will connect to localhost - on the port given by C{serverAddress}. + Create a client end point that will connect to the given address. @type serverAddress: L{IPv4Address} """ - return TCP4ClientEndpoint( - reactor, '127.0.0.1', serverAddress.port) + return TCP4ClientEndpoint(reactor, self.interface, serverAddress.port) - def test_interface(self): - """ - L{IReactorTCP.connectTCP} returns an object providing L{IConnector}. - """ - reactor = self.buildReactor() - connector = reactor.connectTCP("127.0.0.1", 1234, ClientFactory()) - self.assertTrue(verifyObject(IConnector, connector)) +class TCP6Creator(TCPCreator): + """ + Create IPv6 TCP endpoints for + C{ReactorBuilder.runProtocolsWithReactor}-based tests. + + The endpoint types in question here are still the TCP4 variety, since + these simply pass through IPv6 address literals to the reactor, and we are + only testing address literals, not name resolution (as name resolution has + not yet been implemented). See http://twistedmatrix.com/trac/ticket/4470 + for more specific information about new endpoint classes. The naming is + slightly misleading, but presumably if you're passing an IPv6 literal, you + know what you're asking for. + """ + def __init__(self): + self.interface = getLinkLocalIPv6Address() - def test_clientConnectionFailedStopsReactor(self): - """ - The reactor can be stopped by a client factory's - C{clientConnectionFailed} method. - """ - host, port = findFreePort() - reactor = self.buildReactor() - reactor.connectTCP(host, port, Stop(reactor)) - self.runReactor(reactor) - def test_addresses(self): +class TCPClientTestsBase(ReactorBuilder, ConnectionTestsMixin, + TCPClientTestsMixin): + """ + Base class for builders defining tests related to L{IReactorTCP.connectTCP}. + """ + requiredInterfaces = (IReactorTCP,) + + port = 1234 + + @property + def interface(self): """ - A client's transport's C{getHost} and C{getPeer} return L{IPv4Address} - instances which give the dotted-quad string form of the local and - remote endpoints of the connection respectively. + Return the interface attribute from the endpoints object. """ - host, port = findFreePort() - reactor = self.buildReactor() + return self.endpoints.interface - server = reactor.listenTCP( - 0, serverFactoryFor(Protocol), interface=host) - serverAddress = server.getHost() - addresses = {'host': None, 'peer': None} - class CheckAddress(Protocol): - def makeConnection(self, transport): - addresses['host'] = transport.getHost() - addresses['peer'] = transport.getPeer() - reactor.stop() - clientFactory = Stop(reactor) - clientFactory.protocol = CheckAddress - reactor.connectTCP( - 'localhost', server.getHost().port, clientFactory, - bindAddress=('127.0.0.1', port)) +class TCP4ClientTestsBuilder(TCPClientTestsBase): + """ + Builder configured with IPv4 parameters for tests related to + L{IReactorTCP.connectTCP}. + """ + fakeDomainName = 'some-fake.domain.example.com' + family = socket.AF_INET + addressClass = IPv4Address - reactor.installResolver(FakeResolver({'localhost': '127.0.0.1'})) - self.runReactor(reactor) + endpoints = TCPCreator() - self.assertEqual( - addresses['host'], - IPv4Address('TCP', '127.0.0.1', port)) - self.assertEqual( - addresses['peer'], - IPv4Address('TCP', '127.0.0.1', serverAddress.port)) - def test_connectEvent(self): +class TCP6ClientTestsBuilder(TCPClientTestsBase): + """ + Builder configured with IPv6 parameters for tests related to + L{IReactorTCP.connectTCP}. + """ + if ipv6Skip: + skip = ipv6Skip + + family = socket.AF_INET6 + addressClass = IPv6Address + + def setUp(self): + # Only create this object here, so that it won't be created if tests + # are being skipped: + self.endpoints = TCP6Creator() + # This is used by test_addresses to test the distinction between the + # resolved name and the name on the socket itself. All the same + # invariants should hold, but giving back an IPv6 address from a + # resolver is not something the reactor can handle, so instead, we make + # it so that the connect call for the IPv6 address test simply uses an + # address literal. + self.fakeDomainName = self.endpoints.interface + + + +class TCPConnectorTestsBuilder(ReactorBuilder): + """ + Tests for the L{IConnector} provider returned by L{IReactorTCP.connectTCP}. + """ + requiredInterfaces = (IReactorTCP,) + + def test_connectorIdentity(self): """ - This test checks that we correctly get notifications event for a - client. This ought to prevent a regression under Windows using the GTK2 - reactor. See #3925. + L{IReactorTCP.connectTCP} returns an object which provides + L{IConnector}. The destination of the connector is the address which + was passed to C{connectTCP}. The same connector object is passed to + the factory's C{startedConnecting} method as to the factory's + C{clientConnectionLost} method. """ + serverFactory = ClosingFactory() reactor = self.buildReactor() + tcpPort = reactor.listenTCP(0, serverFactory, interface=self.interface) + serverFactory.port = tcpPort + portNumber = tcpPort.getHost().port - server = reactor.listenTCP(0, serverFactoryFor(Protocol)) - connected = [] + seenConnectors = [] + seenFailures = [] - class CheckConnection(Protocol): - def connectionMade(self): - connected.append(self) - reactor.stop() + clientFactory = ClientStartStopFactory() + clientFactory.clientConnectionLost = ( + lambda connector, reason: (seenConnectors.append(connector), + seenFailures.append(reason))) + clientFactory.startedConnecting = seenConnectors.append - clientFactory = Stop(reactor) - clientFactory.protocol = CheckConnection - reactor.connectTCP( - '127.0.0.1', server.getHost().port, clientFactory) + connector = reactor.connectTCP(self.interface, portNumber, + clientFactory) + self.assertTrue(IConnector.providedBy(connector)) + dest = connector.getDestination() + self.assertEqual(dest.type, "TCP") + self.assertEqual(dest.host, self.interface) + self.assertEqual(dest.port, portNumber) - reactor.run() + clientFactory.whenStopped.addBoth(lambda _: reactor.stop()) - self.assertTrue(connected) + self.runReactor(reactor) + seenFailures[0].trap(ConnectionDone) + self.assertEqual(seenConnectors, [connector, connector]) - def test_unregisterProducerAfterDisconnect(self): + + def test_userFail(self): """ - If a producer is unregistered from a L{ITCPTransport} provider after the - transport has been disconnected (by the peer) and after - L{ITCPTransport.loseConnection} has been called, the transport is not - re-added to the reactor as a writer as would be necessary if the - transport were still connected. + Calling L{IConnector.stopConnecting} in C{Factory.startedConnecting} + results in C{Factory.clientConnectionFailed} being called with + L{error.UserError} as the reason. """ + serverFactory = MyServerFactory() reactor = self.buildReactor() - port = reactor.listenTCP(0, serverFactoryFor(ClosingProtocol)) + tcpPort = reactor.listenTCP(0, serverFactory, interface=self.interface) + portNumber = tcpPort.getHost().port - finished = Deferred() - finished.addErrback(log.err) - finished.addCallback(lambda ign: reactor.stop()) + fatalErrors = [] - writing = [] + def startedConnecting(connector): + try: + connector.stopConnecting() + except Exception: + fatalErrors.append(Failure()) + reactor.stop() - class ClientProtocol(Protocol): - """ - Protocol to connect, register a producer, try to lose the - connection, wait for the server to disconnect from us, and - then unregister the producer. - """ - def connectionMade(self): - log.msg("ClientProtocol.connectionMade") - self.transport.registerProducer( - _SimplePullProducer(self.transport), False) - self.transport.loseConnection() + clientFactory = ClientStartStopFactory() + clientFactory.startedConnecting = startedConnecting + + clientFactory.whenStopped.addBoth(lambda _: reactor.stop()) + + reactor.callWhenRunning(lambda: reactor.connectTCP(self.interface, + portNumber, + clientFactory)) - def connectionLost(self, reason): - log.msg("ClientProtocol.connectionLost") - self.unregister() - writing.append(self.transport in _getWriters(reactor)) - finished.callback(None) - - def unregister(self): - log.msg("ClientProtocol unregister") - self.transport.unregisterProducer() - - clientFactory = ClientFactory() - clientFactory.protocol = ClientProtocol - reactor.connectTCP('127.0.0.1', port.getHost().port, clientFactory) self.runReactor(reactor) - self.assertFalse( - writing[0], "Transport was writing after unregisterProducer.") + + if fatalErrors: + self.fail(fatalErrors[0].getTraceback()) + clientFactory.reason.trap(UserError) + self.assertEqual(clientFactory.failed, 1) - def test_disconnectWhileProducing(self): + def test_reconnect(self): """ - If L{ITCPTransport.loseConnection} is called while a producer - is registered with the transport, the connection is closed - after the producer is unregistered. + Calling L{IConnector.connect} in C{Factory.clientConnectionLost} causes + a new connection attempt to be made. """ + serverFactory = ClosingFactory() reactor = self.buildReactor() + tcpPort = reactor.listenTCP(0, serverFactory, interface=self.interface) + serverFactory.port = tcpPort + portNumber = tcpPort.getHost().port - # For some reason, pyobject/pygtk will not deliver the close - # notification that should happen after the unregisterProducer call in - # this test. The selectable is in the write notification set, but no - # notification ever arrives. Probably for the same reason #5233 led - # win32eventreactor to be broken. - skippedReactors = ["Glib2Reactor", "Gtk2Reactor"] - reactorClassName = reactor.__class__.__name__ - if reactorClassName in skippedReactors and platform.isWindows(): - raise SkipTest( - "A pygobject/pygtk bug disables this functionality on Windows.") + clientFactory = MyClientFactory() - class Producer: - def resumeProducing(self): - log.msg("Producer.resumeProducing") + def clientConnectionLost(connector, reason): + connector.connect() + clientFactory.clientConnectionLost = clientConnectionLost + reactor.connectTCP(self.interface, portNumber, clientFactory) + + protocolMadeAndClosed = [] + def reconnectFailed(ignored): + p = clientFactory.protocol + protocolMadeAndClosed.append((p.made, p.closed)) + reactor.stop() - port = reactor.listenTCP(0, serverFactoryFor(Protocol)) + clientFactory.failDeferred.addCallback(reconnectFailed) - finished = Deferred() - finished.addErrback(log.err) - finished.addCallback(lambda ign: reactor.stop()) + self.runReactor(reactor) - class ClientProtocol(Protocol): - """ - Protocol to connect, register a producer, try to lose the - connection, unregister the producer, and wait for the connection to - actually be lost. - """ - def connectionMade(self): - log.msg("ClientProtocol.connectionMade") - self.transport.registerProducer(Producer(), False) - self.transport.loseConnection() - # Let the reactor tick over, in case synchronously calling - # loseConnection and then unregisterProducer is the same as - # synchronously calling unregisterProducer and then - # loseConnection (as it is in several reactors). - reactor.callLater(0, reactor.callLater, 0, self.unregister) - - def unregister(self): - log.msg("ClientProtocol unregister") - self.transport.unregisterProducer() - # This should all be pretty quick. Fail the test - # if we don't get a connectionLost event really - # soon. - reactor.callLater( - 1.0, finished.errback, - Failure(Exception("Connection was not lost"))) + clientFactory.reason.trap(ConnectionRefusedError) + self.assertEqual(protocolMadeAndClosed, [(1, 1)]) - def connectionLost(self, reason): - log.msg("ClientProtocol.connectionLost") - finished.callback(None) - clientFactory = ClientFactory() - clientFactory.protocol = ClientProtocol - reactor.connectTCP('127.0.0.1', port.getHost().port, clientFactory) - self.runReactor(reactor) - # If the test failed, we logged an error already and trial - # will catch it. +class TCP4ConnectorTestsBuilder(TCPConnectorTestsBuilder): + interface = '127.0.0.1' + family = socket.AF_INET + addressClass = IPv4Address - def test_badContext(self): - """ - If the context factory passed to L{ITCPTransport.startTLS} raises an - exception from its C{getContext} method, that exception is raised by - L{ITCPTransport.startTLS}. - """ - reactor = self.buildReactor() - brokenFactory = BrokenContextFactory() - exception = [None] - serverFactory = ServerFactory() - serverFactory.protocol = Protocol +class TCP6ConnectorTestsBuilder(TCPConnectorTestsBuilder): + family = socket.AF_INET6 + addressClass = IPv6Address - port = reactor.listenTCP(0, serverFactory) - endpoint = self.clientEndpoint(reactor, port.getHost()) + if ipv6Skip: + skip = ipv6Skip - clientFactory = ClientFactory() - clientFactory.protocol = Protocol - connectDeferred = endpoint.connect(clientFactory) - - def connected(protocol): - if not ITLSTransport.providedBy(protocol.transport): - exception[0] = "skip" - else: - exception[0] = self.assertRaises( - ValueError, protocol.transport.startTLS, brokenFactory) + def setUp(self): + self.interface = getLinkLocalIPv6Address() - connectDeferred.addCallback(connected) - connectDeferred.addErrback(log.err, "Unexpected startTLS behavior") - connectDeferred.addCallback(lambda ign: reactor.stop()) - self.runReactor(reactor) - if exception[0] == "skip": - raise SkipTest("Reactor does not support ITLSTransport") - self.assertEqual(BrokenContextFactory.message, str(exception[0])) +def createTestSocket(test, addressFamily, socketType): + """ + Create a socket for the duration of the given test. + + @param test: the test to add cleanup to. + + @param addressFamily: an C{AF_*} constant + + @param socketType: a C{SOCK_*} constant. + + @return: a socket object. + """ + skt = socket.socket(addressFamily, socketType) + test.addCleanup(skt.close) + return skt @@ -734,24 +632,66 @@ self.assertFullyNewStyle(port) - -class TCPPortTestsBuilder(ReactorBuilder, ObjectModelIntegrationMixin, - StreamTransportTestsMixin): +class ListenTCPMixin(object): """ - Tests for L{IReactorTCP.listenTCP} + Mixin which uses L{IReactorTCP.listenTCP} to hand out listening TCP ports. """ - def getListeningPort(self, reactor, factory): + def getListeningPort(self, reactor, factory, port=0, interface=''): """ Get a TCP port from a reactor. """ - return reactor.listenTCP(0, factory) + return reactor.listenTCP(port, factory, interface=interface) + + + +class SocketTCPMixin(object): + """ + Mixin which uses L{IReactorSocket.adoptStreamPort} to hand out listening TCP + ports. + """ + def getListeningPort(self, reactor, factory, port=0, interface=''): + """ + Get a TCP port from a reactor, wrapping an already-initialized file + descriptor. + """ + if IReactorSocket.providedBy(reactor): + if ':' in interface: + domain = socket.AF_INET6 + address = socket.getaddrinfo(interface, port)[0][4] + else: + domain = socket.AF_INET + address = (interface, port) + portSock = socket.socket(domain) + portSock.bind(address) + portSock.listen(3) + portSock.setblocking(False) + try: + return reactor.adoptStreamPort( + portSock.fileno(), portSock.family, factory) + finally: + # The socket should still be open; fileno will raise if it is + # not. + portSock.fileno() + # Now clean it up, because the rest of the test does not need + # it. + portSock.close() + else: + raise SkipTest("Reactor does not provide IReactorSocket") + +class TCPPortTestsMixin(object): + """ + Tests for L{IReactorTCP.listenTCP} + """ + requiredInterfaces = (IReactorTCP,) + def getExpectedStartListeningLogMessage(self, port, factory): """ Get the message expected to be logged when a TCP port starts listening. """ - return "%s starting on %d" % (factory, port.getHost().port) + return "%s starting on %d" % ( + factory, port.getHost().port) def getExpectedConnectionLostLogMsg(self, port): @@ -767,7 +707,7 @@ listening port listens on an IPv4 address. """ reactor = self.buildReactor() - port = reactor.listenTCP(0, ServerFactory()) + port = self.getListeningPort(reactor, ServerFactory()) address = port.getHost() self.assertIsInstance(address, IPv4Address) @@ -781,7 +721,8 @@ reactor = self.buildReactor() host, portNumber = findFreePort( family=socket.AF_INET6, interface='::1')[:2] - port = reactor.listenTCP(portNumber, ServerFactory(), interface=host) + port = self.getListeningPort( + reactor, ServerFactory(), portNumber, host) address = port.getHost() self.assertIsInstance(address, IPv6Address) self.assertEqual('::1', address.host) @@ -799,7 +740,7 @@ """ linkLocal = getLinkLocalIPv6Address() reactor = self.buildReactor() - port = reactor.listenTCP(0, ServerFactory(), interface=linkLocal) + port = self.getListeningPort(reactor, ServerFactory(), 0, linkLocal) address = port.getHost() self.assertIsInstance(address, IPv6Address) self.assertEqual(linkLocal, address.host) @@ -833,7 +774,7 @@ factory = ObserveAddress() reactor = self.buildReactor() - port = reactor.listenTCP(0, factory, interface=interface) + port = self.getListeningPort(reactor, factory, 0, interface) client.setblocking(False) try: connect(client, (port.getHost().host, port.getHost().port)) @@ -851,8 +792,7 @@ to the factory's C{buildProtocol} method giving the peer's address. """ interface = '127.0.0.1' - client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET, socket.SOCK_STREAM) observedAddress = self._buildProtocolAddressTest(client, interface) self.assertEqual( IPv4Address('TCP', *client.getsockname()), observedAddress) @@ -865,8 +805,7 @@ address. """ interface = '::1' - client = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET6, socket.SOCK_STREAM) observedAddress = self._buildProtocolAddressTest(client, interface) self.assertEqual( IPv6Address('TCP', *client.getsockname()[:2]), observedAddress) @@ -877,12 +816,11 @@ def test_buildProtocolIPv6AddressScopeID(self): """ When a connection is accepted to a link-local IPv6 address, an - L{IPv6Address} is passed to the factory's C{buildProtocol} method giving - the peer's address, including a scope identifier. + L{IPv6Address} is passed to the factory's C{buildProtocol} method + giving the peer's address, including a scope identifier. """ interface = getLinkLocalIPv6Address() - client = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET6, socket.SOCK_STREAM) observedAddress = self._buildProtocolAddressTest(client, interface) self.assertEqual( IPv6Address('TCP', *client.getsockname()[:2]), observedAddress) @@ -918,7 +856,7 @@ reactor = self.buildReactor() factory = ServerFactory() factory.protocol = ObserveAddress - port = reactor.listenTCP(0, factory, interface=interface) + port = self.getListeningPort(reactor, factory, 0, interface) client.setblocking(False) try: connect(client, (port.getHost().host, port.getHost().port)) @@ -935,8 +873,7 @@ address on which the server accepted the connection. """ interface = '127.0.0.1' - client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET, socket.SOCK_STREAM) hostAddress = self._serverGetConnectionAddressTest( client, interface, 'getHost') self.assertEqual( @@ -950,8 +887,7 @@ address on which the server accepted the connection. """ interface = '::1' - client = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET6, socket.SOCK_STREAM) hostAddress = self._serverGetConnectionAddressTest( client, interface, 'getHost') self.assertEqual( @@ -968,8 +904,7 @@ identifier. """ interface = getLinkLocalIPv6Address() - client = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET6, socket.SOCK_STREAM) hostAddress = self._serverGetConnectionAddressTest( client, interface, 'getHost') self.assertEqual( @@ -985,8 +920,7 @@ address of the remote end of the connection. """ interface = '127.0.0.1' - client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET, socket.SOCK_STREAM) peerAddress = self._serverGetConnectionAddressTest( client, interface, 'getPeer') self.assertEqual( @@ -1000,8 +934,7 @@ address on the remote end of the connection. """ interface = '::1' - client = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET6, socket.SOCK_STREAM) peerAddress = self._serverGetConnectionAddressTest( client, interface, 'getPeer') self.assertEqual( @@ -1018,8 +951,7 @@ identifier. """ interface = getLinkLocalIPv6Address() - client = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - self.addCleanup(client.close) + client = createTestSocket(self, socket.AF_INET6, socket.SOCK_STREAM) peerAddress = self._serverGetConnectionAddressTest( client, interface, 'getPeer') self.assertEqual( @@ -1029,10 +961,25 @@ +class TCPPortTestsBuilder(ReactorBuilder, ListenTCPMixin, TCPPortTestsMixin, + ObjectModelIntegrationMixin, + StreamTransportTestsMixin): + pass + + + +class TCPFDPortTestsBuilder(ReactorBuilder, SocketTCPMixin, TCPPortTestsMixin, + ObjectModelIntegrationMixin, + StreamTransportTestsMixin): + pass + + + class StopStartReadingProtocol(Protocol): """ Protocol that pauses and resumes the transport a few times """ + def connectionMade(self): self.data = '' self.pauseResumeProducing(3) @@ -1064,6 +1011,8 @@ """ Builder defining tests relating to L{twisted.internet.tcp.Connection}. """ + requiredInterfaces = (IReactorTCP,) + def test_stopStartReading(self): """ This test verifies transport socket read state after multiple @@ -1110,8 +1059,8 @@ cf = ClientFactory() cf.protocol = Protocol d = DeferredList([cc.connect(cf), sf.ready]).addCallback(proceed, p) + d.addErrback(log.err) self.runReactor(reactor) - return d def test_connectionLostAfterPausedTransport(self): @@ -1129,38 +1078,32 @@ The reactor needs to remember that notification until Bob resumes the transport. """ - reactor = self.buildReactor() - events = [] - class Pauser(Protocol): + class Pauser(ConnectableProtocol): + def __init__(self): + self.events = [] + def dataReceived(self, bytes): - events.append("paused") + self.events.append("paused") self.transport.pauseProducing() - reactor.callLater(0, self.resume) + self.reactor.callLater(0, self.resume) def resume(self): - events.append("resumed") + self.events.append("resumed") self.transport.resumeProducing() def connectionLost(self, reason): # This is the event you have been waiting for. - events.append("lost") - reactor.stop() + self.events.append("lost") + ConnectableProtocol.connectionLost(self, reason) - serverFactory = ServerFactory() - serverFactory.protocol = Pauser - port = reactor.listenTCP(0, serverFactory) - - cc = TCP4ClientEndpoint(reactor, '127.0.0.1', port.getHost().port) - cf = ClientFactory() - cf.protocol = Protocol - clientDeferred = cc.connect(cf) - def connected(client): - client.transport.write("some bytes for you") - client.transport.loseConnection() - clientDeferred.addCallback(connected) + class Client(ConnectableProtocol): + def connectionMade(self): + self.transport.write("some bytes for you") + self.transport.loseConnection() - self.runReactor(reactor) - self.assertEqual(events, ["paused", "resumed", "lost"]) + pauser = Pauser() + runProtocolsWithReactor(self, pauser, Client(), TCPCreator()) + self.assertEqual(pauser.events, ["paused", "resumed", "lost"]) def test_doubleHalfClose(self): @@ -1171,9 +1114,7 @@ This rather obscure case used to fail (see ticket #3037). """ - reactor = self.buildReactor() - - class ListenerProtocol(Protocol): + class ListenerProtocol(ConnectableProtocol): implements(IHalfCloseableProtocol) def readConnectionLost(self): @@ -1182,48 +1123,21 @@ def writeConnectionLost(self): self.transport.loseConnection() - def connectionLost(self, reason): - reactor.stop() - - factory = ServerFactory() - factory.protocol = ListenerProtocol - port = reactor.listenTCP(0, factory, interface="127.0.0.1") - self.addCleanup(port.stopListening) - - cc = TCP4ClientEndpoint(reactor, '127.0.0.1', port.getHost().port) - cf = ClientFactory() - cf.protocol = Protocol - clientDeferred = cc.connect(cf) - def connected(client): - client.transport.loseWriteConnection() - clientDeferred.addCallback(connected) + class Client(ConnectableProtocol): + def connectionMade(self): + self.transport.loseConnection() # If test fails, reactor won't stop and we'll hit timeout: - self.runReactor(reactor, timeout=1) + runProtocolsWithReactor( + self, ListenerProtocol(), Client(), TCPCreator()) -class WriteSequenceTests(ReactorBuilder): +class WriteSequenceTestsMixin(object): """ Test for L{twisted.internet.abstract.FileDescriptor.writeSequence}. - - @ivar client: the connected client factory to be used in tests. - @type client: L{MyClientFactory} - - @ivar server: the listening server factory to be used in tests. - @type server: L{MyServerFactory} """ - def setUp(self): - server = MyServerFactory() - server.protocolConnectionMade = Deferred() - server.protocolConnectionLost = Deferred() - self.server = server - - client = MyClientFactory() - client.protocolConnectionMade = Deferred() - client.protocolConnectionLost = Deferred() - self.client = client - + requiredInterfaces = (IReactorTCP,) def setWriteBufferSize(self, transport, value): """ @@ -1236,42 +1150,28 @@ transport.bufferSize = value - def test_withoutWrite(self): + def test_writeSequeceWithoutWrite(self): """ C{writeSequence} sends the data even if C{write} hasn't been called. """ - client, server = self.client, self.server - reactor = self.buildReactor() - port = reactor.listenTCP(0, server) - self.addCleanup(port.stopListening) + def connected(protocols): + client, server, port = protocols - connector = reactor.connectTCP( - "127.0.0.1", port.getHost().port, client) - self.addCleanup(connector.disconnect) - - def dataReceived(data): - log.msg("data received: %r" % data) - self.assertEquals(data, "Some sequence splitted") - client.protocol.transport.loseConnection() - - def clientConnected(proto): - log.msg("client connected %s" % proto) - proto.transport.writeSequence(["Some ", "sequence ", "splitted"]) - - def serverConnected(proto): - log.msg("server connected %s" % proto) - proto.dataReceived = dataReceived - - d1 = client.protocolConnectionMade.addCallback(clientConnected) - d2 = server.protocolConnectionMade.addCallback(serverConnected) - d3 = server.protocolConnectionLost - d4 = client.protocolConnectionLost - d = gatherResults([d1, d2, d3, d4]) - def stop(result): - reactor.stop() - return result - d.addBoth(stop) + def dataReceived(data): + log.msg("data received: %r" % data) + self.assertEqual(data, "Some sequence splitted") + client.transport.loseConnection() + + server.dataReceived = dataReceived + + client.transport.writeSequence(["Some ", "sequence ", "splitted"]) + + reactor = self.buildReactor() + d = self.getConnectedClientAndServer(reactor, "127.0.0.1", + socket.AF_INET) + d.addCallback(connected) + d.addErrback(log.err) self.runReactor(reactor) @@ -1280,77 +1180,23 @@ C{writeSequence} with an element in the sequence of type unicode raises C{TypeError}. """ - client, server = self.client, self.server - reactor = self.buildReactor() - - port = reactor.listenTCP(0, server) - self.addCleanup(port.stopListening) - connector = reactor.connectTCP( - "127.0.0.1", port.getHost().port, client) - self.addCleanup(connector.disconnect) + def connected(protocols): + client, server, port = protocols - def serverConnected(proto): - log.msg("server connected %s" % proto) exc = self.assertRaises( TypeError, - proto.transport.writeSequence, [u"Unicode is not kosher"]) - self.assertEquals(str(exc), "Data must not be unicode") + server.transport.writeSequence, [u"Unicode is not kosher"]) - d = server.protocolConnectionMade.addCallback(serverConnected) - d.addErrback(log.err) - d.addCallback(lambda ignored: reactor.stop()) - - self.runReactor(reactor) + self.assertEqual(str(exc), "Data must not be unicode") + server.transport.loseConnection() - def _producerTest(self, clientConnected): - """ - Helper for testing producers which call C{writeSequence}. This will set - up a connection which a producer can use. It returns after the - connection is closed. - - @param clientConnected: A callback which will be invoked with a client - protocol after a connection is setup. This is responsible for - setting up some sort of producer. - """ reactor = self.buildReactor() - - port = reactor.listenTCP(0, self.server) - self.addCleanup(port.stopListening) - - connector = reactor.connectTCP( - "127.0.0.1", port.getHost().port, self.client) - self.addCleanup(connector.disconnect) - - # The following could probably all be much simpler, but for #5285. - - # First let the server notice the connection - d1 = self.server.protocolConnectionMade - - # Grab the client connection Deferred now though, so we don't lose it if - # the client connects before the server. - d2 = self.client.protocolConnectionMade - - def serverConnected(proto): - # Now take action as soon as the client is connected - d2.addCallback(clientConnected) - return d2 - d1.addCallback(serverConnected) - - d3 = self.server.protocolConnectionLost - d4 = self.client.protocolConnectionLost - - # After the client is connected and does its producer stuff, wait for - # the disconnection events. - def didProducerActions(ignored): - return gatherResults([d3, d4]) - d1.addCallback(didProducerActions) - - def stop(result): - reactor.stop() - return result - d1.addBoth(stop) + d = self.getConnectedClientAndServer(reactor, "127.0.0.1", + socket.AF_INET) + d.addCallback(connected) + d.addErrback(log.err) self.runReactor(reactor) @@ -1359,10 +1205,12 @@ C{writeSequence} pauses its streaming producer if too much data is buffered, and then resumes it. """ - client, server = self.client, self.server class SaveActionProducer(object): implements(IPushProducer) + client = None + server = None + def __init__(self): self.actions = [] @@ -1372,31 +1220,39 @@ def resumeProducing(self): self.actions.append("resume") # Unregister the producer so the connection can close - client.protocol.transport.unregisterProducer() + self.client.transport.unregisterProducer() # This is why the code below waits for the server connection - # first - so we have it to close here. We close the server side - # because win32evenreactor cannot reliably observe us closing - # the client side (#5285). - server.protocol.transport.loseConnection() + # first - so we have it to close here. We close the server + # side because win32evenreactor cannot reliably observe us + # closing the client side (#5285). + self.server.transport.loseConnection() def stopProducing(self): self.actions.append("stop") producer = SaveActionProducer() - def clientConnected(proto): - # Register a streaming producer and verify that it gets paused after - # it writes more than the local send buffer can hold. - proto.transport.registerProducer(producer, True) - self.assertEquals(producer.actions, []) - self.setWriteBufferSize(proto.transport, 500) - proto.transport.writeSequence(["x" * 50] * 20) - self.assertEquals(producer.actions, ["pause"]) - - self._producerTest(clientConnected) + def connected(protocols): + client, server = protocols[:2] + producer.client = client + producer.server = server + # Register a streaming producer and verify that it gets paused + # after it writes more than the local send buffer can hold. + client.transport.registerProducer(producer, True) + self.assertEqual(producer.actions, []) + self.setWriteBufferSize(client.transport, 500) + client.transport.writeSequence(["x" * 50] * 20) + self.assertEqual(producer.actions, ["pause"]) + + reactor = self.buildReactor() + d = self.getConnectedClientAndServer(reactor, "127.0.0.1", + socket.AF_INET) + d.addCallback(connected) + d.addErrback(log.err) + self.runReactor(reactor) # After the send buffer gets a chance to empty out a bit, the producer # should be resumed. - self.assertEquals(producer.actions, ["pause", "resume"]) + self.assertEqual(producer.actions, ["pause", "resume"]) def test_nonStreamingProducer(self): @@ -1404,58 +1260,243 @@ C{writeSequence} pauses its producer if too much data is buffered only if this is a streaming producer. """ - client, server = self.client, self.server test = self class SaveActionProducer(object): implements(IPullProducer) + client = None + def __init__(self): self.actions = [] def resumeProducing(self): self.actions.append("resume") if self.actions.count("resume") == 2: - client.protocol.transport.stopConsuming() + self.client.transport.stopConsuming() else: - test.setWriteBufferSize(client.protocol.transport, 500) - client.protocol.transport.writeSequence(["x" * 50] * 20) + test.setWriteBufferSize(self.client.transport, 500) + self.client.transport.writeSequence(["x" * 50] * 20) def stopProducing(self): self.actions.append("stop") + producer = SaveActionProducer() - def clientConnected(proto): + def connected(protocols): + client = protocols[0] + producer.client = client # Register a non-streaming producer and verify that it is resumed # immediately. - proto.transport.registerProducer(producer, False) - self.assertEquals(producer.actions, ["resume"]) + client.transport.registerProducer(producer, False) + self.assertEqual(producer.actions, ["resume"]) - self._producerTest(clientConnected) + reactor = self.buildReactor() + d = self.getConnectedClientAndServer(reactor, "127.0.0.1", + socket.AF_INET) + d.addCallback(connected) + d.addErrback(log.err) + self.runReactor(reactor) # After the local send buffer empties out, the producer should be # resumed again. - self.assertEquals(producer.actions, ["resume", "resume"]) + self.assertEqual(producer.actions, ["resume", "resume"]) -globals().update(TCPClientTestsBuilder.makeTestCaseClasses()) -globals().update(TCPPortTestsBuilder.makeTestCaseClasses()) -globals().update(TCPConnectionTestsBuilder.makeTestCaseClasses()) -globals().update(WriteSequenceTests.makeTestCaseClasses()) +class TCPTransportServerAddressTestMixin(object): + """ + Test mixing for TCP server address building and log prefix. + """ + + def getConnectedClientAndServer(self, reactor, interface, addressFamily): + """ + Helper method returnine a L{Deferred} firing with a tuple of a client + protocol, a server protocol, and a running TCP port. + """ + raise NotImplementedError() + + + def _testServerAddress(self, interface, addressFamily, adressClass): + """ + Helper method to test TCP server addresses on either IPv4 or IPv6. + """ + + def connected(protocols): + client, server, port = protocols + + self.assertEqual( + "" % + (server.transport.sessionno, port.getHost().port), + str(server.transport)) + self.assertEqual( + "AccumulatingProtocol,%s,%s" % + (server.transport.sessionno, interface), + server.transport.logstr) -class AbortServerProtocol(Protocol): + [peerAddress] = server.factory.peerAddresses + self.assertIsInstance(peerAddress, adressClass) + self.assertEqual('TCP', peerAddress.type) + self.assertEqual(interface, peerAddress.host) + + server.transport.loseConnection() + + reactor = self.buildReactor() + d = self.getConnectedClientAndServer(reactor, interface, addressFamily) + d.addCallback(connected) + d.addErrback(log.err) + self.runReactor(reactor) + + + def test_serverAddressTCP4(self): + """ + L{Server} instances have a string representation indicating on which + port they're running, and the connected address is stored on the + C{peerAddresses} attribute of the factory. + """ + return self._testServerAddress("127.0.0.1", socket.AF_INET, + IPv4Address) + + + def test_serverAddressTCP6(self): + """ + IPv6 L{Server} instances have a string representation indicating on + which port they're running, and the connected address is stored on the + C{peerAddresses} attribute of the factory. + """ + return self._testServerAddress(getLinkLocalIPv6Address(), + socket.AF_INET6, IPv6Address) + + if ipv6Skip: + test_serverAddressTCP6.skip = ipv6Skip + + + +class TCPTransportTestsBuilder(TCPTransportServerAddressTestMixin, + WriteSequenceTestsMixin, ReactorBuilder): """ - Generic server protocol for abortConnection() tests. + Test standard L{ITCPTransport}s built with C{listenTCP} and C{connectTCP}. """ - def connectionLost(self, reason): - self.factory.done.callback(reason) - del self.factory.done + def getConnectedClientAndServer(self, reactor, interface, addressFamily): + """ + Return a L{Deferred} firing with a L{MyClientFactory} and + L{MyServerFactory} connected pair, and the listening C{Port}. + """ + server = MyServerFactory() + server.protocolConnectionMade = Deferred() + server.protocolConnectionLost = Deferred() + + client = MyClientFactory() + client.protocolConnectionMade = Deferred() + client.protocolConnectionLost = Deferred() + + port = reactor.listenTCP(0, server, interface=interface) + + lostDeferred = gatherResults([client.protocolConnectionLost, + server.protocolConnectionLost]) + def stop(result): + reactor.stop() + return result + + lostDeferred.addBoth(stop) + + startDeferred = gatherResults([client.protocolConnectionMade, + server.protocolConnectionMade]) + + deferred = Deferred() + + def start(protocols): + client, server = protocols + log.msg("client connected %s" % client) + log.msg("server connected %s" % server) + deferred.callback((client, server, port)) + startDeferred.addCallback(start) + reactor.connectTCP(interface, port.getHost().port, client) -class ServerAbortsTwice(AbortServerProtocol): + return deferred + + + +class AdoptStreamConnectionTestsBuilder(TCPTransportServerAddressTestMixin, + WriteSequenceTestsMixin, + ReactorBuilder): + """ + Test server transports built using C{adoptStreamConnection}. + """ + + requiredInterfaces = (IReactorFDSet, IReactorSocket) + + def getConnectedClientAndServer(self, reactor, interface, addressFamily): + """ + Return a L{Deferred} firing with a L{MyClientFactory} and + L{MyServerFactory} connected pair, and the listening C{Port}. The + particularity is that the server protocol has been obtained after doing + a C{adoptStreamConnection} against the original server connection. + """ + firstServer = MyServerFactory() + firstServer.protocolConnectionMade = Deferred() + + server = MyServerFactory() + server.protocolConnectionMade = Deferred() + server.protocolConnectionLost = Deferred() + + client = MyClientFactory() + client.protocolConnectionMade = Deferred() + client.protocolConnectionLost = Deferred() + + port = reactor.listenTCP(0, firstServer, interface=interface) + + def firtServerConnected(proto): + reactor.removeReader(proto.transport) + reactor.removeWriter(proto.transport) + reactor.adoptStreamConnection( + proto.transport.fileno(), addressFamily, server) + + firstServer.protocolConnectionMade.addCallback(firtServerConnected) + + lostDeferred = gatherResults([client.protocolConnectionLost, + server.protocolConnectionLost]) + def stop(result): + if reactor.running: + reactor.stop() + return result + + lostDeferred.addBoth(stop) + + deferred = Deferred() + deferred.addErrback(stop) + + startDeferred = gatherResults([client.protocolConnectionMade, + server.protocolConnectionMade]) + def start(protocols): + client, server = protocols + log.msg("client connected %s" % client) + log.msg("server connected %s" % server) + deferred.callback((client, server, port)) + + startDeferred.addCallback(start) + + reactor.connectTCP(interface, port.getHost().port, client) + return deferred + + + +globals().update(TCP4ClientTestsBuilder.makeTestCaseClasses()) +globals().update(TCP6ClientTestsBuilder.makeTestCaseClasses()) +globals().update(TCPPortTestsBuilder.makeTestCaseClasses()) +globals().update(TCPFDPortTestsBuilder.makeTestCaseClasses()) +globals().update(TCPConnectionTestsBuilder.makeTestCaseClasses()) +globals().update(TCP4ConnectorTestsBuilder.makeTestCaseClasses()) +globals().update(TCP6ConnectorTestsBuilder.makeTestCaseClasses()) +globals().update(TCPTransportTestsBuilder.makeTestCaseClasses()) +globals().update(AdoptStreamConnectionTestsBuilder.makeTestCaseClasses()) + + + +class ServerAbortsTwice(ConnectableProtocol): """ Call abortConnection() twice. """ @@ -1466,7 +1507,7 @@ -class ServerAbortsThenLoses(AbortServerProtocol): +class ServerAbortsThenLoses(ConnectableProtocol): """ Call abortConnection() followed by loseConnection(). """ @@ -1477,7 +1518,7 @@ -class AbortServerWritingProtocol(AbortServerProtocol): +class AbortServerWritingProtocol(ConnectableProtocol): """ Protocol that writes data upon connection. """ @@ -1503,7 +1544,7 @@ -class NoReadServer(AbortServerProtocol): +class NoReadServer(ConnectableProtocol): """ Stop reading immediately on connection. @@ -1516,7 +1557,7 @@ -class EventualNoReadServer(AbortServerProtocol): +class EventualNoReadServer(ConnectableProtocol): """ Like NoReadServer, except we Wait until some bytes have been delivered before stopping reading. This means TLS handshake has finished, where @@ -1551,40 +1592,16 @@ -class AbortServerFactory(ServerFactory): - """ - Server factory for abortConnection() tests. - """ - - def __init__(self, done, serverClass, reactor): - self.done = done - self.serverClass = serverClass - self.reactor = reactor - - def buildProtocol(self, addr): - p = self.serverClass() - p.factory = self - self.proto = p - return p - - -class BaseAbortingClient(Protocol): +class BaseAbortingClient(ConnectableProtocol): """ Base class for abort-testing clients. """ - inReactorMethod = False - def __init__(self, done, reactor): - self.done = done - self.reactor = reactor - - def connectionLost(self, reason): if self.inReactorMethod: raise RuntimeError("BUG: connectionLost was called re-entrantly!") - self.done.callback(reason) - del self.done + ConnectableProtocol.connectionLost(self, reason) @@ -1644,18 +1661,13 @@ -class ProducerAbortingClient(Protocol): +class ProducerAbortingClient(ConnectableProtocol): """ Call abortConnection from doWrite, via resumeProducing. """ inReactorMethod = True - - def __init__(self, done, reactor): - self.done = done - self.reactor = reactor - self.producerStopped = False - + producerStopped = False def write(self): self.transport.write("lalala" * 127000) @@ -1684,12 +1696,11 @@ raise RuntimeError("BUG: stopProducing() was never called.") if self.inReactorMethod: raise RuntimeError("BUG: connectionLost called re-entrantly!") - self.done.callback(reason) - del self.done + ConnectableProtocol.connectionLost(self, reason) -class StreamingProducerClient(Protocol): +class StreamingProducerClient(ConnectableProtocol): """ Call abortConnection() when the other side has stopped reading. @@ -1701,14 +1712,9 @@ Since it's very difficult to know when this actually happens, we just write a lot of data, and assume at that point no more writes will happen. """ - - def __init__(self, done, reactor): - self.done = done - self.paused = False - self.reactor = reactor - self.extraWrites = 0 - self.inReactorMethod = False - + paused = False + extraWrites = 0 + inReactorMethod = False def connectionMade(self): self.write() @@ -1764,9 +1770,8 @@ def connectionLost(self, reason): # Tell server to start reading again so it knows to go away: - self.serverFactory.proto.transport.startReading() - self.done.callback(reason) - del self.done + self.otherProtocol.transport.startReading() + ConnectableProtocol.connectionLost(self, reason) @@ -1831,8 +1836,7 @@ # Base class assertion about stopProducing being called isn't valid; # if the we blew up in resumeProducing, consumers are justified in # giving up on the producer and not calling stopProducing. - self.done.callback(reason) - del self.done + ConnectableProtocol.connectionLost(self, reason) @@ -1840,6 +1844,8 @@ """ Unit tests for L{ITransport.abortConnection}. """ + # Override in subclasses, should be a EndpointCreator instance: + endpoints = None def runAbortTest(self, clientClass, serverClass, clientConnectionLostReason=None): @@ -1850,63 +1856,34 @@ We then run the reactor until both sides have disconnected, and then verify that the right exception resulted. """ - reactor = self.buildReactor() - serverDoneDeferred = Deferred() - clientDoneDeferred = Deferred() - - server = AbortServerFactory(serverDoneDeferred, serverClass, reactor) - serverport = self.listen(reactor, server) - - c = ClientCreator(reactor, clientClass, clientDoneDeferred, reactor) - d = self.connect(c, serverport) - def addServer(client): - client.serverFactory = server - d.addCallback(addServer) - - serverReason = [] - clientReason = [] - serverDoneDeferred.addBoth(serverReason.append) - clientDoneDeferred.addBoth(clientReason.append) - d.addCallback(lambda x: clientDoneDeferred) - d.addCallback(lambda x: serverDoneDeferred) - - d.addCallback(lambda x: serverport.stopListening()) - def verifyReactorIsClean(ignore): - if clientConnectionLostReason is not None: - self.flushLoggedErrors(clientConnectionLostReason) - self.assertEqual(reactor.removeAll(), []) - # The reactor always has a timeout added in buildReactor(): - delayedCalls = reactor.getDelayedCalls() - self.assertEqual(len(delayedCalls), 1, map(str, delayedCalls)) - d.addCallback(verifyReactorIsClean) - - d.addCallback(lambda ignored: reactor.stop()) - # If we get error, make sure test still exits: - def errorHandler(err): - log.err(err) - reactor.stop() - d.addErrback(errorHandler) - - self.runReactor(reactor, timeout=10) - clientExpectedExceptions = (ConnectionAborted, ConnectionLost) serverExpectedExceptions = (ConnectionLost, ConnectionDone) # In TLS tests we may get SSL.Error instead of ConnectionLost, # since we're trashing the TLS protocol layer. - try: - from OpenSSL import SSL - except ImportError: - SSL = None - if SSL: + if useSSL: clientExpectedExceptions = clientExpectedExceptions + (SSL.Error,) serverExpectedExceptions = serverExpectedExceptions + (SSL.Error,) - if clientConnectionLostReason: - self.assertIsInstance(clientReason[0].value, - (clientConnectionLostReason,) + clientExpectedExceptions) + client = clientClass() + server = serverClass() + client.otherProtocol = server + server.otherProtocol = client + reactor = runProtocolsWithReactor(self, server, client, self.endpoints) + + # Make sure everything was shutdown correctly: + self.assertEqual(reactor.removeAll(), []) + # The reactor always has a timeout added in runReactor(): + delayedCalls = reactor.getDelayedCalls() + self.assertEqual(len(delayedCalls), 1, map(str, delayedCalls)) + + if clientConnectionLostReason is not None: + self.assertIsInstance( + client.disconnectReason.value, + (clientConnectionLostReason,) + clientExpectedExceptions) else: - self.assertIsInstance(clientReason[0].value, clientExpectedExceptions) - self.assertIsInstance(serverReason[0].value, serverExpectedExceptions) + self.assertIsInstance(client.disconnectReason.value, + clientExpectedExceptions) + self.assertIsInstance(server.disconnectReason.value, serverExpectedExceptions) def test_dataReceivedAbort(self): @@ -1964,7 +1941,7 @@ connectionLost should not be called re-entrantly. """ self.runAbortTest(ProducerAbortingClient, - AbortServerProtocol) + ConnectableProtocol) def test_resumeProducingAbortLater(self): @@ -2015,6 +1992,8 @@ self.runAbortTest(DataReceivedRaisingClient, AbortServerWritingProtocol, clientConnectionLostReason=ZeroDivisionError) + errors = self.flushLoggedErrors(ZeroDivisionError) + self.assertEqual(len(errors), 1) def test_resumeProducingThrows(self): @@ -2027,9 +2006,10 @@ unexpected exceptions. """ self.runAbortTest(ResumeThrowsClient, - AbortServerProtocol, + ConnectableProtocol, clientConnectionLostReason=ZeroDivisionError) - + errors = self.flushLoggedErrors(ZeroDivisionError) + self.assertEqual(len(errors), 1) @@ -2037,20 +2017,61 @@ """ TCP-specific L{AbortConnectionMixin} tests. """ + requiredInterfaces = (IReactorTCP,) + + endpoints = TCPCreator() + +globals().update(AbortConnectionTestCase.makeTestCaseClasses()) + + - def listen(self, reactor, server): +class SimpleUtilityTestCase(TestCase): + """ + Simple, direct tests for helpers within L{twisted.internet.tcp}. + """ + if ipv6Skip: + skip = ipv6Skip + + def test_resolveNumericHost(self): """ - Listen with the given protocol factory. + L{_resolveIPv6} raises a L{socket.gaierror} (L{socket.EAI_NONAME}) when + invoked with a non-numeric host. (In other words, it is passing + L{socket.AI_NUMERICHOST} to L{socket.getaddrinfo} and will not + accidentally block if it receives bad input.) """ - return reactor.listenTCP(0, server, interface="127.0.0.1") + err = self.assertRaises(socket.gaierror, _resolveIPv6, "localhost", 1) + self.assertEqual(err.args[0], socket.EAI_NONAME) - def connect(self, clientcreator, serverport, *a, **k): + def test_resolveNumericService(self): """ - Connect a client to the listening server port. Return the resulting - Deferred. + L{_resolveIPv6} raises a L{socket.gaierror} (L{socket.EAI_NONAME}) when + invoked with a non-numeric port. (In other words, it is passing + L{socket.AI_NUMERICSERV} to L{socket.getaddrinfo} and will not + accidentally block if it receives bad input.) """ - return clientcreator.connectTCP(serverport.getHost().host, - serverport.getHost().port) + err = self.assertRaises(socket.gaierror, _resolveIPv6, "::1", "http") + self.assertEqual(err.args[0], socket.EAI_NONAME) -globals().update(AbortConnectionTestCase.makeTestCaseClasses()) + if platform.isWindows(): + test_resolveNumericService.skip = ("The AI_NUMERICSERV flag is not " + "supported by Microsoft providers.") + # http://msdn.microsoft.com/en-us/library/windows/desktop/ms738520.aspx + + + def test_resolveIPv6(self): + """ + L{_resolveIPv6} discovers the flow info and scope ID of an IPv6 + address. + """ + result = _resolveIPv6("::1", 2) + self.assertEqual(len(result), 4) + # We can't say anything more useful about these than that they're + # integers, because the whole point of getaddrinfo is that you can never + # know a-priori know _anything_ about the network interfaces of the + # computer that you're on and you have to ask it. + self.assertIsInstance(result[2], int) # flow info + self.assertIsInstance(result[3], int) # scope id + # but, luckily, IP presentation format and what it means to be a port + # number are a little better specified. + self.assertEqual(result[:2], ("::1", 2)) diff -Nru twisted-12.0.0/twisted/internet/test/test_threads.py twisted-12.2.0/twisted/internet/test/test_threads.py --- twisted-12.0.0/twisted/internet/test/test_threads.py 2011-12-08 03:37:41.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_threads.py 2012-07-14 14:04:36.000000000 +0000 @@ -13,12 +13,15 @@ from twisted.python.threadable import isInIOThread from twisted.internet.test.reactormixins import ReactorBuilder from twisted.python.threadpool import ThreadPool +from twisted.internet.interfaces import IReactorThreads class ThreadTestsBuilder(ReactorBuilder): """ Builder for defining tests relating to L{IReactorThreads}. """ + requiredInterfaces = (IReactorThreads,) + def test_getThreadPool(self): """ C{reactor.getThreadPool()} returns an instance of L{ThreadPool} which diff -Nru twisted-12.0.0/twisted/internet/test/test_time.py twisted-12.2.0/twisted/internet/test/test_time.py --- twisted-12.0.0/twisted/internet/test/test_time.py 2011-12-08 03:37:41.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_time.py 2012-07-14 14:04:36.000000000 +0000 @@ -9,12 +9,15 @@ from twisted.python.runtime import platform from twisted.internet.test.reactormixins import ReactorBuilder +from twisted.internet.interfaces import IReactorTime class TimeTestsBuilder(ReactorBuilder): """ Builder for defining tests relating to L{IReactorTime}. """ + requiredInterfaces = (IReactorTime,) + def test_delayedCallStopsReactor(self): """ The reactor can be stopped by a delayed call. @@ -30,6 +33,8 @@ Builder for defining tests relating to L{IReactorTime} for reactors based off glib. """ + requiredInterfaces = (IReactorTime,) + if platform.isWindows(): _reactors = ["twisted.internet.gtk2reactor.PortableGtkReactor"] else: diff -Nru twisted-12.0.0/twisted/internet/test/test_tls.py twisted-12.2.0/twisted/internet/test/test_tls.py --- twisted-12.0.0/twisted/internet/test/test_tls.py 2012-01-22 00:48:15.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_tls.py 2012-05-12 10:07:03.000000000 +0000 @@ -7,9 +7,11 @@ __metaclass__ = type +import sys, operator + from zope.interface import implements -from twisted.internet.test.reactormixins import ReactorBuilder +from twisted.internet.test.reactormixins import ReactorBuilder, EndpointCreator from twisted.internet.protocol import ServerFactory, ClientFactory, Protocol from twisted.internet.interfaces import ( IReactorSSL, ITLSTransport, IStreamClientEndpoint) @@ -18,14 +20,14 @@ SSL4ServerEndpoint, SSL4ClientEndpoint, TCP4ClientEndpoint) from twisted.internet.error import ConnectionClosed from twisted.internet.task import Cooperator -from twisted.trial.unittest import SkipTest +from twisted.trial.unittest import TestCase, SkipTest from twisted.python.runtime import platform from twisted.internet.test.test_core import ObjectModelIntegrationMixin -from twisted.internet.test.test_tcp import StreamTransportTestsMixin -from twisted.internet.test.connectionmixins import ConnectionTestsMixin from twisted.internet.test.test_tcp import ( - BrokenContextFactory, AbortConnectionMixin) + StreamTransportTestsMixin, AbortConnectionMixin) +from twisted.internet.test.connectionmixins import ConnectionTestsMixin +from twisted.internet.test.connectionmixins import BrokenContextFactory try: from OpenSSL.crypto import FILETYPE_PEM @@ -121,22 +123,27 @@ immediately start TLS on it. Return a L{Deferred} which fires with the protocol instance. """ - d = self.wrapped.connect(factory) - def connected(protocol): - protocol.transport.startTLS(self.contextFactory) - return protocol - d.addCallback(connected) - return d + # This would be cleaner when we have ITransport.switchProtocol, which + # will be added with ticket #3204: + class WrapperFactory(ServerFactory): + def buildProtocol(wrapperSelf, addr): + protocol = factory.buildProtocol(addr) + def connectionMade(orig=protocol.connectionMade): + protocol.transport.startTLS(self.contextFactory) + orig() + protocol.connectionMade = connectionMade + return protocol + return self.wrapped.connect(WrapperFactory()) -class StartTLSClientTestsMixin(TLSMixin, ReactorBuilder, ConnectionTestsMixin, - ContextGeneratingMixin): + +class StartTLSClientCreator(EndpointCreator, ContextGeneratingMixin): """ - Tests for TLS connections established using L{ITLSTransport.startTLS} (as - opposed to L{IReactorSSL.connectSSL} or L{IReactorSSL.listenSSL}). + Create L{ITLSTransport.startTLS} endpoint for the client, and normal SSL + for server just because it's easier. """ - def serverEndpoint(self, reactor): + def server(self, reactor): """ Construct an SSL server endpoint. This should be be constructing a TCP server endpoint which immediately calls C{startTLS} instead, but that @@ -145,7 +152,7 @@ return SSL4ServerEndpoint(reactor, 0, self.getServerContext()) - def clientEndpoint(self, reactor, serverAddress): + def client(self, reactor, serverAddress): """ Construct a TCP client endpoint wrapped to immediately start TLS. """ @@ -179,20 +186,27 @@ -class SSLClientTestsMixin(TLSMixin, ReactorBuilder, ContextGeneratingMixin, - ConnectionTestsMixin, BadContextTestsMixin): +class StartTLSClientTestsMixin(TLSMixin, ReactorBuilder, ConnectionTestsMixin): """ - Mixin defining tests relating to L{ITLSTransport}. + Tests for TLS connections established using L{ITLSTransport.startTLS} (as + opposed to L{IReactorSSL.connectSSL} or L{IReactorSSL.listenSSL}). """ + endpoints = StartTLSClientCreator() + - def serverEndpoint(self, reactor): + +class SSLCreator(EndpointCreator, ContextGeneratingMixin): + """ + Create SSL endpoints. + """ + def server(self, reactor): """ Create an SSL server endpoint on a TCP/IP-stack allocated port. """ return SSL4ServerEndpoint(reactor, 0, self.getServerContext()) - def clientEndpoint(self, reactor, serverAddress): + def client(self, reactor, serverAddress): """ Create an SSL client endpoint which will connect localhost on the port given by C{serverAddress}. @@ -204,6 +218,13 @@ ClientContextFactory()) +class SSLClientTestsMixin(TLSMixin, ReactorBuilder, ContextGeneratingMixin, + ConnectionTestsMixin, BadContextTestsMixin): + """ + Mixin defining tests relating to L{ITLSTransport}. + """ + endpoints = SSLCreator() + def test_badContext(self): """ If the context factory passed to L{IReactorSSL.connectSSL} raises an @@ -338,7 +359,11 @@ class AbortSSLConnectionTest(ReactorBuilder, AbortConnectionMixin, ContextGeneratingMixin): + """ + C{abortConnection} tests using SSL. + """ requiredInterfaces = (IReactorSSL,) + endpoints = SSLCreator() def buildReactor(self): reactor = ReactorBuilder.buildReactor(self) @@ -358,25 +383,50 @@ def setUp(self): if FILETYPE_PEM is None: raise SkipTest("OpenSSL not available.") - self.serverContext = self.getServerContext() - self.clientContext = self.getClientContext() - self.clientContext.method = self.serverContext.method - - - def listen(self, reactor, server): - """ - Listen using SSL. - """ - return reactor.listenSSL( - 0, server, self.serverContext, interface="127.0.0.1") +globals().update(AbortSSLConnectionTest.makeTestCaseClasses()) - def connect(self, clientcreator, serverport): +class OldTLSDeprecationTest(TestCase): + """ + Tests for the deprecation of L{twisted.internet._oldtls}, the implementation + module for L{IReactorSSL} used when only an old version of pyOpenSSL is + available. + """ + def test_warning(self): """ - Connect using SSL. + The use of L{twisted.internet._oldtls} is deprecated, and emits a + L{DeprecationWarning}. """ - return clientcreator.connectSSL( - serverport.getHost().host, serverport.getHost().port, - self.clientContext) + # Since _oldtls depends on OpenSSL, just skip this test if it isn't + # installed on the system. Faking it would be error prone. + try: + import OpenSSL + except ImportError: + raise SkipTest("OpenSSL not available.") -globals().update(AbortSSLConnectionTest.makeTestCaseClasses()) + # Change the apparent version of OpenSSL to one support for which is + # deprecated. And have it change back again after the test. + self.patch(OpenSSL, '__version__', '0.5') + + # If the module was already imported, the import statement below won't + # execute its top-level code. Take it out of sys.modules so the import + # system re-evaluates it. Arrange to put the original back afterwards. + # Also handle the case where it hasn't yet been imported. + try: + oldtls = sys.modules['twisted.internet._oldtls'] + except KeyError: + self.addCleanup(sys.modules.pop, 'twisted.internet._oldtls') + else: + del sys.modules['twisted.internet._oldtls'] + self.addCleanup( + operator.setitem, sys.modules, 'twisted.internet._oldtls', + oldtls) + + # The actual test. + import twisted.internet._oldtls + warnings = self.flushWarnings() + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual( + warnings[0]['message'], + "Support for pyOpenSSL 0.5 is deprecated. " + "Upgrade to pyOpenSSL 0.10 or newer.") diff -Nru twisted-12.0.0/twisted/internet/test/test_udp.py twisted-12.2.0/twisted/internet/test/test_udp.py --- twisted-12.0.0/twisted/internet/test/test_udp.py 2011-10-16 19:41:49.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_udp.py 2012-07-14 14:04:36.000000000 +0000 @@ -16,7 +16,8 @@ from twisted.python.log import ILogContext, err from twisted.internet.test.reactormixins import ReactorBuilder from twisted.internet.defer import Deferred, maybeDeferred -from twisted.internet.interfaces import ILoggingContext, IListeningPort +from twisted.internet.interfaces import ( + ILoggingContext, IListeningPort, IReactorUDP) from twisted.internet.address import IPv4Address from twisted.internet.protocol import DatagramProtocol @@ -133,6 +134,8 @@ """ Builder defining tests relating to L{IReactorUDP.listenUDP}. """ + requiredInterfaces = (IReactorUDP,) + def test_interface(self): """ L{IReactorUDP.listenUDP} returns an object providing L{IListeningPort}. diff -Nru twisted-12.0.0/twisted/internet/test/test_unix.py twisted-12.2.0/twisted/internet/test/test_unix.py --- twisted-12.0.0/twisted/internet/test/test_unix.py 2011-11-02 13:15:43.000000000 +0000 +++ twisted-12.2.0/twisted/internet/test/test_unix.py 2012-07-14 14:04:36.000000000 +0000 @@ -6,37 +6,53 @@ """ from stat import S_IMODE -from os import stat -from sys import platform +from os import stat, close from tempfile import mktemp +from socket import AF_INET, SOCK_STREAM, socket +from pprint import pformat try: from socket import AF_UNIX except ImportError: AF_UNIX = None +from zope.interface import implements from zope.interface.verify import verifyObject +from twisted.python.log import addObserver, removeObserver, err +from twisted.python.failure import Failure from twisted.python.hashlib import md5 -from twisted.internet.interfaces import IConnector +from twisted.python.runtime import platform +from twisted.internet.interfaces import ( + IConnector, IFileDescriptorReceiver, IReactorUNIX) +from twisted.internet.error import ConnectionClosed, FileDescriptorOverrun from twisted.internet.address import UNIXAddress from twisted.internet.endpoints import UNIXServerEndpoint, UNIXClientEndpoint +from twisted.internet.defer import Deferred, fail +from twisted.internet.task import LoopingCall from twisted.internet import interfaces from twisted.internet.protocol import ( ServerFactory, ClientFactory, DatagramProtocol) -from twisted.internet.test.reactormixins import ReactorBuilder +from twisted.internet.test.reactormixins import ReactorBuilder, EndpointCreator from twisted.internet.test.test_core import ObjectModelIntegrationMixin from twisted.internet.test.test_tcp import StreamTransportTestsMixin +from twisted.internet.test.reactormixins import ( + ConnectableProtocol, runProtocolsWithReactor) from twisted.internet.test.connectionmixins import ConnectionTestsMixin +try: + from twisted.python import sendmsg +except ImportError: + sendmsgSkip = ( + "sendmsg extension unavailable, extended UNIX features disabled") +else: + sendmsgSkip = None + class UNIXFamilyMixin: """ Test-helper defining mixin for things related to AF_UNIX sockets. """ - if AF_UNIX is None: - skip = "Platform does not support AF_UNIX sockets" - def _modeTest(self, methodName, path, factory): """ Assert that the mode of the created unix socket is set to the mode @@ -59,11 +75,14 @@ return md5(case.mktemp()).hexdigest() -class UNIXTestsBuilder(UNIXFamilyMixin, ReactorBuilder, ConnectionTestsMixin): + +class UNIXCreator(EndpointCreator): """ - Builder defining tests relating to L{IReactorUNIX}. + Create UNIX socket end points. """ - def serverEndpoint(self, reactor): + requiredInterfaces = (interfaces.IReactorUNIX,) + + def server(self, reactor): """ Construct a UNIX server endpoint. """ @@ -72,13 +91,127 @@ return UNIXServerEndpoint(reactor, path) - def clientEndpoint(self, reactor, serverAddress): + def client(self, reactor, serverAddress): """ Construct a UNIX client endpoint. """ return UNIXClientEndpoint(reactor, serverAddress.name) + +class SendFileDescriptor(ConnectableProtocol): + """ + L{SendFileDescriptorAndBytes} sends a file descriptor and optionally some + normal bytes and then closes its connection. + + @ivar reason: The reason the connection was lost, after C{connectionLost} + is called. + """ + reason = None + + def __init__(self, fd, data): + """ + @param fd: A C{int} giving a file descriptor to send over the + connection. + + @param data: A C{str} giving data to send over the connection, or + C{None} if no data is to be sent. + """ + self.fd = fd + self.data = data + + + def connectionMade(self): + """ + Send C{self.fd} and, if it is not C{None}, C{self.data}. Then close the + connection. + """ + self.transport.sendFileDescriptor(self.fd) + if self.data: + self.transport.write(self.data) + self.transport.loseConnection() + + + def connectionLost(self, reason): + ConnectableProtocol.connectionLost(self, reason) + self.reason = reason + + + +class ReceiveFileDescriptor(ConnectableProtocol): + """ + L{ReceiveFileDescriptor} provides an API for waiting for file descriptors to + be received. + + @ivar reason: The reason the connection was lost, after C{connectionLost} + is called. + + @ivar waiting: A L{Deferred} which fires with a file descriptor once one is + received, or with a failure if the connection is lost with no descriptor + arriving. + """ + implements(IFileDescriptorReceiver) + + reason = None + waiting = None + + def waitForDescriptor(self): + """ + Return a L{Deferred} which will fire with the next file descriptor + received, or with a failure if the connection is or has already been + lost. + """ + if self.reason is None: + self.waiting = Deferred() + return self.waiting + else: + return fail(self.reason) + + + def fileDescriptorReceived(self, descriptor): + """ + Fire the waiting Deferred, initialized by C{waitForDescriptor}, with the + file descriptor just received. + """ + self.waiting.callback(descriptor) + self.waiting = None + + + def dataReceived(self, data): + """ + Fail the waiting Deferred, if it has not already been fired by + C{fileDescriptorReceived}. The bytes sent along with a file descriptor + are guaranteed to be delivered to the protocol's C{dataReceived} method + only after the file descriptor has been delivered to the protocol's + C{fileDescriptorReceived}. + """ + if self.waiting is not None: + self.waiting.errback(Failure(Exception( + "Received bytes (%r) before descriptor." % (data,)))) + self.waiting = None + + + def connectionLost(self, reason): + """ + Fail the waiting Deferred, initialized by C{waitForDescriptor}, if there + is one. + """ + ConnectableProtocol.connectionLost(self, reason) + if self.waiting is not None: + self.waiting.errback(reason) + self.waiting = None + self.reason = reason + + + +class UNIXTestsBuilder(UNIXFamilyMixin, ReactorBuilder, ConnectionTestsMixin): + """ + Builder defining tests relating to L{IReactorUNIX}. + """ + requiredInterfaces = (IReactorUNIX,) + + endpoints = UNIXCreator() + def test_interface(self): """ L{IReactorUNIX.connectUNIX} returns an object providing L{IConnector}. @@ -107,7 +240,7 @@ reactor = self.buildReactor() port = reactor.listenUNIX('\0' + path, ServerFactory()) self.assertEqual(port.getHost(), UNIXAddress('\0' + path)) - if platform != 'linux2': + if not platform.isLinux(): test_listenOnLinuxAbstractNamespace.skip = ( 'Abstract namespace UNIX sockets only supported on Linux.') @@ -122,16 +255,246 @@ connector = reactor.connectUNIX('\0' + path, ClientFactory()) self.assertEqual( connector.getDestination(), UNIXAddress('\0' + path)) - if platform != 'linux2': + if not platform.isLinux(): test_connectToLinuxAbstractNamespace.skip = ( 'Abstract namespace UNIX sockets only supported on Linux.') + def test_addresses(self): + """ + A client's transport's C{getHost} and C{getPeer} return L{UNIXAddress} + instances which have the filesystem path of the host and peer ends of + the connection. + """ + class SaveAddress(ConnectableProtocol): + def makeConnection(self, transport): + self.addresses = dict( + host=transport.getHost(), peer=transport.getPeer()) + transport.loseConnection() + + server = SaveAddress() + client = SaveAddress() + + runProtocolsWithReactor(self, server, client, self.endpoints) + + self.assertEqual(server.addresses['host'], client.addresses['peer']) + self.assertEqual(server.addresses['peer'], client.addresses['host']) + + + def test_sendFileDescriptor(self): + """ + L{IUNIXTransport.sendFileDescriptor} accepts an integer file descriptor + and sends a copy of it to the process reading from the connection. + """ + from socket import fromfd + + s = socket() + s.bind(('', 0)) + server = SendFileDescriptor(s.fileno(), "junk") + + client = ReceiveFileDescriptor() + d = client.waitForDescriptor() + def checkDescriptor(descriptor): + received = fromfd(descriptor, AF_INET, SOCK_STREAM) + # Thanks for the free dup, fromfd() + close(descriptor) + + # If the sockets have the same local address, they're probably the + # same. + self.assertEqual(s.getsockname(), received.getsockname()) + + # But it would be cheating for them to be identified by the same + # file descriptor. The point was to get a copy, as we might get if + # there were two processes involved here. + self.assertNotEqual(s.fileno(), received.fileno()) + d.addCallback(checkDescriptor) + d.addErrback(err, "Sending file descriptor encountered a problem") + d.addBoth(lambda ignored: server.transport.loseConnection()) + + runProtocolsWithReactor(self, server, client, self.endpoints) + if sendmsgSkip is not None: + test_sendFileDescriptor.skip = sendmsgSkip + + + def test_sendFileDescriptorTriggersPauseProducing(self): + """ + If a L{IUNIXTransport.sendFileDescriptor} call fills up the send buffer, + any registered producer is paused. + """ + class DoesNotRead(ConnectableProtocol): + def connectionMade(self): + self.transport.pauseProducing() + + class SendsManyFileDescriptors(ConnectableProtocol): + paused = False + + def connectionMade(self): + self.socket = socket() + self.transport.registerProducer(self, True) + def sender(): + self.transport.sendFileDescriptor(self.socket.fileno()) + self.transport.write("x") + self.task = LoopingCall(sender) + self.task.clock = self.transport.reactor + self.task.start(0).addErrback(err, "Send loop failure") + + def stopProducing(self): + self._disconnect() + + def resumeProducing(self): + self._disconnect() + + def pauseProducing(self): + self.paused = True + self.transport.unregisterProducer() + self._disconnect() + + def _disconnect(self): + self.task.stop() + self.transport.abortConnection() + self.other.transport.abortConnection() + + server = SendsManyFileDescriptors() + client = DoesNotRead() + server.other = client + runProtocolsWithReactor(self, server, client, self.endpoints) + + self.assertTrue( + server.paused, "sendFileDescriptor producer was not paused") + if sendmsgSkip is not None: + test_sendFileDescriptorTriggersPauseProducing.skip = sendmsgSkip + + + def test_fileDescriptorOverrun(self): + """ + If L{IUNIXTransport.sendFileDescriptor} is used to queue a greater + number of file descriptors than the number of bytes sent using + L{ITransport.write}, the connection is closed and the protocol connected + to the transport has its C{connectionLost} method called with a failure + wrapping L{FileDescriptorOverrun}. + """ + cargo = socket() + server = SendFileDescriptor(cargo.fileno(), None) + + client = ReceiveFileDescriptor() + d = self.assertFailure( + client.waitForDescriptor(), ConnectionClosed) + d.addErrback( + err, "Sending file descriptor encountered unexpected problem") + d.addBoth(lambda ignored: server.transport.loseConnection()) + + runProtocolsWithReactor(self, server, client, self.endpoints) + + self.assertIsInstance(server.reason.value, FileDescriptorOverrun) + if sendmsgSkip is not None: + test_fileDescriptorOverrun.skip = sendmsgSkip + + + def test_avoidLeakingFileDescriptors(self): + """ + If associated with a protocol which does not provide + L{IFileDescriptorReceiver}, file descriptors received by the + L{IUNIXTransport} implementation are closed and a warning is emitted. + """ + # To verify this, establish a connection. Send one end of the + # connection over the IUNIXTransport implementation. After the copy + # should no longer exist, close the original. If the opposite end of + # the connection decides the connection is closed, the copy does not + # exist. + from socket import socketpair + probeClient, probeServer = socketpair() + + events = [] + addObserver(events.append) + self.addCleanup(removeObserver, events.append) + + class RecordEndpointAddresses(SendFileDescriptor): + def connectionMade(self): + self.hostAddress = self.transport.getHost() + self.peerAddress = self.transport.getPeer() + SendFileDescriptor.connectionMade(self) + + server = RecordEndpointAddresses(probeClient.fileno(), "junk") + client = ConnectableProtocol() + + runProtocolsWithReactor(self, server, client, self.endpoints) + + # Get rid of the original reference to the socket. + probeClient.close() + + # A non-blocking recv will return "" if the connection is closed, as + # desired. If the connection has not been closed, because the duplicate + # file descriptor is still open, it will fail with EAGAIN instead. + probeServer.setblocking(False) + self.assertEqual("", probeServer.recv(1024)) + + # This is a surprising circumstance, so it should be logged. + format = ( + "%(protocolName)s (on %(hostAddress)r) does not " + "provide IFileDescriptorReceiver; closing file " + "descriptor received (from %(peerAddress)r).") + clsName = "ConnectableProtocol" + + # Reverse host and peer, since the log event is from the client + # perspective. + expectedEvent = dict(hostAddress=server.peerAddress, + peerAddress=server.hostAddress, + protocolName=clsName, + format=format) + + for logEvent in events: + for k, v in expectedEvent.iteritems(): + if v != logEvent.get(k): + break + else: + # No mismatches were found, stop looking at events + break + else: + # No fully matching events were found, fail the test. + self.fail( + "Expected event (%s) not found in logged events (%s)" % ( + expectedEvent, pformat(events,))) + if sendmsgSkip is not None: + test_avoidLeakingFileDescriptors.skip = sendmsgSkip + + + def test_descriptorDeliveredBeforeBytes(self): + """ + L{IUNIXTransport.sendFileDescriptor} sends file descriptors before + L{ITransport.write} sends normal bytes. + """ + class RecordEvents(ConnectableProtocol): + implements(IFileDescriptorReceiver) + + def connectionMade(self): + ConnectableProtocol.connectionMade(self) + self.events = [] + + def fileDescriptorReceived(innerSelf, descriptor): + self.addCleanup(close, descriptor) + innerSelf.events.append(type(descriptor)) + + def dataReceived(self, data): + self.events.extend(data) + + cargo = socket() + server = SendFileDescriptor(cargo.fileno(), "junk") + client = RecordEvents() + + runProtocolsWithReactor(self, server, client, self.endpoints) + + self.assertEqual([int, "j", "u", "n", "k"], client.events) + if sendmsgSkip is not None: + test_descriptorDeliveredBeforeBytes.skip = sendmsgSkip + + class UNIXDatagramTestsBuilder(UNIXFamilyMixin, ReactorBuilder): """ Builder defining tests relating to L{IReactorUNIXDatagram}. """ + requiredInterfaces = (interfaces.IReactorUNIXDatagram,) + # There's no corresponding test_connectMode because the mode parameter to # connectUNIXDatagram has been completely ignored since that API was first # introduced. @@ -153,7 +516,7 @@ reactor = self.buildReactor() port = reactor.listenUNIXDatagram('\0' + path, DatagramProtocol()) self.assertEqual(port.getHost(), UNIXAddress('\0' + path)) - if platform != 'linux2': + if not platform.isLinux(): test_listenOnLinuxAbstractNamespace.skip = ( 'Abstract namespace UNIX sockets only supported on Linux.') @@ -164,7 +527,7 @@ """ Tests for L{IReactorUNIX.listenUnix} """ - requiredInterfaces = [interfaces.IReactorUNIX] + requiredInterfaces = (interfaces.IReactorUNIX,) def getListeningPort(self, reactor, factory): """ diff -Nru twisted-12.0.0/twisted/internet/unix.py twisted-12.2.0/twisted/internet/unix.py --- twisted-12.0.0/twisted/internet/unix.py 2011-10-11 12:01:26.000000000 +0000 +++ twisted-12.2.0/twisted/internet/unix.py 2012-04-26 13:46:20.000000000 +0000 @@ -12,8 +12,8 @@ """ # System imports -import os, sys, stat, socket -from errno import EINTR, EMSGSIZE, EAGAIN, EWOULDBLOCK, ECONNREFUSED +import os, sys, stat, socket, struct +from errno import EINTR, EMSGSIZE, EAGAIN, EWOULDBLOCK, ECONNREFUSED, ENOBUFS from zope.interface import implements, implementsOnly, implementedBy @@ -21,20 +21,190 @@ raise ImportError("UNIX sockets not supported on this platform") # Twisted imports -from twisted.internet import base, tcp, udp, error, interfaces, protocol, address +from twisted.internet import main, base, tcp, udp, error, interfaces, protocol, address from twisted.internet.error import CannotListenError +from twisted.python.util import untilConcludes from twisted.python import lockfile, log, reflect, failure +try: + from twisted.python import sendmsg +except ImportError: + sendmsg = None + + +def _ancillaryDescriptor(fd): + """ + Pack an integer into an ancillary data structure suitable for use with + L{sendmsg.send1msg}. + """ + packed = struct.pack("i", fd) + return [(socket.SOL_SOCKET, sendmsg.SCM_RIGHTS, packed)] + + + +class _SendmsgMixin(object): + """ + Mixin for stream-oriented UNIX transports which uses sendmsg and recvmsg to + offer additional functionality, such as copying file descriptors into other + processes. + + @ivar _writeSomeDataBase: The class which provides the basic implementation + of C{writeSomeData}. Ultimately this should be a subclass of + L{twisted.internet.abstract.FileDescriptor}. Subclasses which mix in + L{_SendmsgMixin} must define this. + + @ivar _sendmsgQueue: A C{list} of C{int} holding file descriptors which are + currently buffered before being sent. + + @ivar _fileDescriptorBufferSize: An C{int} giving the maximum number of file + descriptors to accept and queue for sending before pausing the + registered producer, if there is one. + """ + implements(interfaces.IUNIXTransport) + + _writeSomeDataBase = None + _fileDescriptorBufferSize = 64 + + def __init__(self): + self._sendmsgQueue = [] + + + def _isSendBufferFull(self): + """ + Determine whether the user-space send buffer for this transport is full + or not. + + This extends the base determination by adding consideration of how many + file descriptors need to be sent using L{sendmsg.send1msg}. When there + are more than C{self._fileDescriptorBufferSize}, the buffer is + considered full. + + @return: C{True} if it is full, C{False} otherwise. + """ + # There must be some bytes in the normal send buffer, checked by + # _writeSomeDataBase._isSendBufferFull, in order to send file + # descriptors from _sendmsgQueue. That means that the buffer will + # eventually be considered full even without this additional logic. + # However, since we send only one byte per file descriptor, having lots + # of elements in _sendmsgQueue incurs more overhead and perhaps slows + # things down. Anyway, try this for now, maybe rethink it later. + return ( + len(self._sendmsgQueue) > self._fileDescriptorBufferSize + or self._writeSomeDataBase._isSendBufferFull(self)) + + + def sendFileDescriptor(self, fileno): + """ + Queue the given file descriptor to be sent and start trying to send it. + """ + self._sendmsgQueue.append(fileno) + self._maybePauseProducer() + self.startWriting() + + + def writeSomeData(self, data): + """ + Send as much of C{data} as possible. Also send any pending file + descriptors. + """ + # Make it a programming error to send more file descriptors than you + # send regular bytes. Otherwise, due to the limitation mentioned below, + # we could end up with file descriptors left, but no bytes to send with + # them, therefore no way to send those file descriptors. + if len(self._sendmsgQueue) > len(data): + return error.FileDescriptorOverrun() + + # If there are file descriptors to send, try sending them first, using a + # little bit of data from the stream-oriented write buffer too. It is + # not possible to send a file descriptor without sending some regular + # data. + index = 0 + try: + while index < len(self._sendmsgQueue): + fd = self._sendmsgQueue[index] + try: + untilConcludes( + sendmsg.send1msg, self.socket.fileno(), data[index], 0, + _ancillaryDescriptor(fd)) + except socket.error, se: + if se.args[0] in (EWOULDBLOCK, ENOBUFS): + return index + else: + return main.CONNECTION_LOST + else: + index += 1 + finally: + del self._sendmsgQueue[:index] + + # Hand the remaining data to the base implementation. Avoid slicing in + # favor of a buffer, in case that happens to be any faster. + limitedData = buffer(data, index) + result = self._writeSomeDataBase.writeSomeData(self, limitedData) + try: + return index + result + except TypeError: + return result + + + def doRead(self): + """ + Calls L{IFileDescriptorReceiver.fileDescriptorReceived} and + L{IProtocol.dataReceived} with all available data. + + This reads up to C{self.bufferSize} bytes of data from its socket, then + dispatches the data to protocol callbacks to be handled. If the + connection is not lost through an error in the underlying recvmsg(), + this function will return the result of the dataReceived call. + """ + try: + data, flags, ancillary = untilConcludes( + sendmsg.recv1msg, self.socket.fileno(), 0, self.bufferSize) + except socket.error, se: + if se.args[0] == EWOULDBLOCK: + return + else: + return main.CONNECTION_LOST + + if ancillary: + fd = struct.unpack('i', ancillary[0][2])[0] + if interfaces.IFileDescriptorReceiver.providedBy(self.protocol): + self.protocol.fileDescriptorReceived(fd) + else: + log.msg( + format=( + "%(protocolName)s (on %(hostAddress)r) does not " + "provide IFileDescriptorReceiver; closing file " + "descriptor received (from %(peerAddress)r)."), + hostAddress=self.getHost(), peerAddress=self.getPeer(), + protocolName=self._getLogPrefix(self.protocol), + ) + os.close(fd) + + return self._dataReceived(data) + +if sendmsg is None: + class _SendmsgMixin(object): + """ + Behaviorless placeholder used when L{twisted.python.sendmsg} is not + available, preventing L{IUNIXTransport} from being supported. + """ + + + +class Server(_SendmsgMixin, tcp.Server): + + _writeSomeDataBase = tcp.Server -class Server(tcp.Server): def __init__(self, sock, protocol, client, server, sessionno, reactor): + _SendmsgMixin.__init__(self) tcp.Server.__init__(self, sock, protocol, (client, None), server, sessionno, reactor) + def getHost(self): return address.UNIXAddress(self.socket.getsockname()) def getPeer(self): - return address.UNIXAddress(self.hostname) + return address.UNIXAddress(self.hostname or None) @@ -149,12 +319,15 @@ -class Client(tcp.BaseClient): +class Client(_SendmsgMixin, tcp.BaseClient): """A client for Unix sockets.""" addressFamily = socket.AF_UNIX socketType = socket.SOCK_STREAM + _writeSomeDataBase = tcp.BaseClient + def __init__(self, filename, connector, reactor=None, checkPID = 0): + _SendmsgMixin.__init__(self) self.connector = connector self.realAddress = self.addr = filename if checkPID and not lockfile.isLocked(filename + ".lock"): diff -Nru twisted-12.0.0/twisted/manhole/explorer.py twisted-12.2.0/twisted/manhole/explorer.py --- twisted-12.0.0/twisted/manhole/explorer.py 2011-03-27 01:37:18.000000000 +0000 +++ twisted-12.2.0/twisted/manhole/explorer.py 2012-06-07 13:15:27.000000000 +0000 @@ -29,7 +29,7 @@ class Pool(UserDict.UserDict): def getExplorer(self, object, identifier): oid = id(object) - if self.data.has_key(oid): + if oid in self.data: # XXX: This potentially returns something with # 'identifier' set to a different value. return self.data[oid] diff -Nru twisted-12.0.0/twisted/manhole/service.py twisted-12.2.0/twisted/manhole/service.py --- twisted-12.0.0/twisted/manhole/service.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/manhole/service.py 2012-06-07 13:15:27.000000000 +0000 @@ -255,7 +255,7 @@ compatMessage = None for client in clients: try: - if not client.capabilities.has_key("Failure"): + if "Failure" not in client.capabilities: if compatMessage is None: compatMessage = origMessage[:] for i in xrange(len(message)): diff -Nru twisted-12.0.0/twisted/persisted/__init__.py twisted-12.2.0/twisted/persisted/__init__.py --- twisted-12.0.0/twisted/persisted/__init__.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/persisted/__init__.py 2012-03-10 15:22:17.000000000 +0000 @@ -4,12 +4,3 @@ """ Twisted Persisted: utilities for managing persistence. """ - - -from twisted.python import versions, deprecate - -deprecate.deprecatedModuleAttribute(versions.Version('twisted', 11, 0, 0), - "Use a different persistence library. This one " - "is no longer maintained.", - __name__, 'journal') - diff -Nru twisted-12.0.0/twisted/persisted/aot.py twisted-12.2.0/twisted/persisted/aot.py --- twisted-12.0.0/twisted/persisted/aot.py 2011-10-22 03:14:14.000000000 +0000 +++ twisted-12.2.0/twisted/persisted/aot.py 2012-06-12 13:20:20.000000000 +0000 @@ -260,7 +260,7 @@ else: exec stringOrFile in ns - if ns.has_key('app'): + if 'app' in ns: return unjellyFromAOT(ns['app']) else: raise ValueError("%s needs to define an 'app', it didn't!" % stringOrFile) @@ -381,7 +381,7 @@ elif c is Copyreg: loadfunc = reflect.namedObject(ao.loadfunc) d = self.unjellyLater(ao.state).addCallback( - lambda result, _l: apply(_l, result), loadfunc) + lambda result, _l: _l(*result), loadfunc) return d #Types @@ -504,7 +504,7 @@ #mutable inside one. The Ref() class will only print the "Ref(..)" around an #object if it has a Reference explicitly attached. - if self.prepared.has_key(id(obj)): + if id(obj) in self.prepared: oldRef = self.prepared[id(obj)] if oldRef.refnum: # it's been referenced already @@ -538,7 +538,7 @@ state = self.jellyToAO(obj.__dict__) retval.setObj(Instance(reflect.qual(obj.__class__), state)) - elif copy_reg.dispatch_table.has_key(objType): + elif objType in copy_reg.dispatch_table: unpickleFunc, state = copy_reg.dispatch_table[objType](obj) retval.setObj(Copyreg( reflect.fullFuncName(unpickleFunc), diff -Nru twisted-12.0.0/twisted/persisted/journal/__init__.py twisted-12.2.0/twisted/persisted/journal/__init__.py --- twisted-12.0.0/twisted/persisted/journal/__init__.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/persisted/journal/__init__.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,12 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Command-journalling persistence framework inspired by Prevayler. - -This package is deprecated since Twisted 11.0. - -Maintainer: Itamar Shtull-Trauring -""" - diff -Nru twisted-12.0.0/twisted/persisted/journal/base.py twisted-12.2.0/twisted/persisted/journal/base.py --- twisted-12.0.0/twisted/persisted/journal/base.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/persisted/journal/base.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,226 +0,0 @@ -# -*- test-case-name: twisted.test.test_journal -*- -# -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# - - -"""Basic classes and interfaces for journal.""" - -from __future__ import nested_scopes - -# system imports -import os, time - -try: - import cPickle as pickle -except ImportError: - import pickle - -# twisted imports -from zope.interface import implements, Interface - - -class Journal: - """All commands to the system get routed through here. - - Subclasses should implement the actual snapshotting capability. - """ - - def __init__(self, log, journaledService): - self.log = log - self.journaledService = journaledService - self.latestIndex = self.log.getCurrentIndex() - - def updateFromLog(self): - """Run all commands from log that haven't been run yet. - - This method should be run on startup to ensure the snapshot - is up-to-date. - """ - snapshotIndex = self.getLastSnapshot() - if snapshotIndex < self.latestIndex: - for cmdtime, command in self.log.getCommandsSince(snapshotIndex + 1): - command.execute(self.journaledService, cmdtime) - - def executeCommand(self, command): - """Log and execute a command.""" - runTime = time.time() - d = self.log.logCommand(command, runTime) - d.addCallback(self._reallyExecute, command, runTime) - return d - - def _reallyExecute(self, index, command, runTime): - """Callback called when logging command is done.""" - result = command.execute(self.journaledService, runTime) - self.latestIndex = index - return result - - def getLastSnapshot(self): - """Return command index of the last snapshot taken.""" - raise NotImplementedError - - def sync(self, *args, **kwargs): - """Save journal to disk, returns Deferred of finish status. - - Subclasses may choose whatever signature is appropriate, or may - not implement this at all. - """ - raise NotImplementedError - - - -class MemoryJournal(Journal): - """Prevayler-like journal that dumps from memory to disk.""" - - def __init__(self, log, journaledService, path, loadedCallback): - self.path = path - if os.path.exists(path): - try: - self.lastSync, obj = pickle.load(open(path, "rb")) - except (IOError, OSError, pickle.UnpicklingError): - self.lastSync, obj = 0, None - loadedCallback(obj) - else: - self.lastSync = 0 - loadedCallback(None) - Journal.__init__(self, log, journaledService) - - def getLastSnapshot(self): - return self.lastSync - - def sync(self, obj): - # make this more reliable at some point - f = open(self.path, "wb") - pickle.dump((self.latestIndex, obj), f, 1) - f.close() - self.lastSync = self.latestIndex - - -class ICommand(Interface): - """A serializable command which interacts with a journaled service.""" - - def execute(journaledService, runTime): - """Run the command and return result.""" - - -class ICommandLog(Interface): - """Interface for command log.""" - - def logCommand(command, runTime): - """Add a command and its run time to the log. - - @return: Deferred of command index. - """ - - def getCurrentIndex(): - """Return index of last command that was logged.""" - - def getCommandsSince(index): - """Return commands who's index >= the given one. - - @return: list of (time, command) tuples, sorted with ascending times. - """ - - -class LoadingService: - """Base class for journalled service used with Wrappables.""" - - def loadObject(self, objType, objId): - """Return object of specified type and id.""" - raise NotImplementedError - - -class Wrappable: - """Base class for objects used with LoadingService.""" - - objectType = None # override in base class - - def getUid(self): - """Return uid for loading with LoadingService.loadObject""" - raise NotImplementedError - - -class WrapperCommand: - - implements(ICommand) - - def __init__(self, methodName, obj, args=(), kwargs={}): - self.obj = obj - self.objId = obj.getUid() - self.objType = obj.objectType - self.methodName = methodName - self.args = args - self.kwargs = kwargs - - def execute(self, svc, commandTime): - if not hasattr(self, "obj"): - obj = svc.loadObject(self.objType, self.objId) - else: - obj = self.obj - return getattr(obj, self.methodName)(*self.args, **self.kwargs) - - def __getstate__(self): - d = self.__dict__.copy() - del d["obj"] - return d - - -def command(methodName, cmdClass=WrapperCommand): - """Wrap a method so it gets turned into command automatically. - - For use with Wrappables. - - Usage:: - - | class Foo(Wrappable): - | objectType = "foo" - | def getUid(self): - | return self.id - | def _bar(self, x): - | return x + 1 - | - | bar = command('_bar') - - The resulting callable will have signature identical to wrapped - function, except that it expects journal as first argument, and - returns a Deferred. - """ - def wrapper(obj, journal, *args, **kwargs): - return journal.executeCommand(cmdClass(methodName, obj, args, kwargs)) - return wrapper - - -class ServiceWrapperCommand: - - implements(ICommand) - - def __init__(self, methodName, args=(), kwargs={}): - self.methodName = methodName - self.args = args - self.kwargs = kwargs - - def execute(self, svc, commandTime): - return getattr(svc, self.methodName)(*self.args, **self.kwargs) - - def __repr__(self): - return "" % (self.methodName, self.args, self.kwargs) - - def __cmp__(self, other): - if hasattr(other, "__dict__"): - return cmp(self.__dict__, other.__dict__) - else: - return 0 - - -def serviceCommand(methodName, cmdClass=ServiceWrapperCommand): - """Wrap methods into commands for a journalled service. - - The resulting callable will have signature identical to wrapped - function, except that it expects journal as first argument, and - returns a Deferred. - """ - def wrapper(obj, journal, *args, **kwargs): - return journal.executeCommand(cmdClass(methodName, args, kwargs)) - return wrapper diff -Nru twisted-12.0.0/twisted/persisted/journal/picklelog.py twisted-12.2.0/twisted/persisted/journal/picklelog.py --- twisted-12.0.0/twisted/persisted/journal/picklelog.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/persisted/journal/picklelog.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -# -# -*- test-case-name: twisted.test.test_journal -*- - -"""Logging that uses pickles. - -TODO: add log that logs to a file. -""" - -# twisted imports -from twisted.persisted import dirdbm -from twisted.internet import defer -from zope.interface import implements - -# sibling imports -import base - - -class DirDBMLog: - """Log pickles to DirDBM directory.""" - - implements(base.ICommandLog) - - def __init__(self, logPath): - self.db = dirdbm.Shelf(logPath) - indexs = map(int, self.db.keys()) - if indexs: - self.currentIndex = max(indexs) - else: - self.currentIndex = 0 - - def logCommand(self, command, time): - """Log a command.""" - self.currentIndex += 1 - self.db[str(self.currentIndex)] = (time, command) - return defer.succeed(1) - - def getCurrentIndex(self): - """Return index of last command logged.""" - return self.currentIndex - - def getCommandsSince(self, index): - result = [] - for i in range(index, self.currentIndex + 1): - result.append(self.db[str(i)]) - return result diff -Nru twisted-12.0.0/twisted/persisted/styles.py twisted-12.2.0/twisted/persisted/styles.py --- twisted-12.0.0/twisted/persisted/styles.py 2011-09-07 18:31:05.000000000 +0000 +++ twisted-12.2.0/twisted/persisted/styles.py 2012-06-07 13:15:27.000000000 +0000 @@ -68,7 +68,7 @@ def unpickleModule(name): 'support function for copy_reg to unpickle module refs' - if oldModules.has_key(name): + if name in oldModules: log.msg("Module has moved: %s" % name) name = oldModules[name] log.msg(name) @@ -202,11 +202,11 @@ bases.reverse() bases.append(self.__class__) # don't forget me!! for base in bases: - if base.__dict__.has_key('persistenceForgets'): + if 'persistenceForgets' in base.__dict__: for slot in base.persistenceForgets: - if dct.has_key(slot): + if slot in dct: del dct[slot] - if base.__dict__.has_key('persistenceVersion'): + if 'persistenceVersion' in base.__dict__: dct['%s.persistenceVersion' % reflect.qual(base)] = base.persistenceVersion return dct @@ -219,7 +219,7 @@ bases.reverse() bases.append(self.__class__) # don't forget me!! # first let's look for old-skool versioned's - if self.__dict__.has_key("persistenceVersion"): + if "persistenceVersion" in self.__dict__: # Hacky heuristic: if more than one class subclasses Versioned, # we'll assume that the higher version number wins for the older @@ -244,7 +244,7 @@ for base in bases: # ugly hack, but it's what the user expects, really if (Versioned not in base.__bases__ and - not base.__dict__.has_key('persistenceVersion')): + 'persistenceVersion' not in base.__dict__): continue currentVers = base.persistenceVersion pverName = '%s.persistenceVersion' % reflect.qual(base) diff -Nru twisted-12.0.0/twisted/plugins/cred_sshkeys.py twisted-12.2.0/twisted/plugins/cred_sshkeys.py --- twisted-12.0.0/twisted/plugins/cred_sshkeys.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/plugins/cred_sshkeys.py 2012-03-12 21:35:11.000000000 +0000 @@ -0,0 +1,51 @@ +# -*- test-case-name: twisted.test.test_strcred -*- +# +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Cred plugin for ssh key login +""" + +from zope.interface import implements + +from twisted import plugin +from twisted.cred.strcred import ICheckerFactory +from twisted.cred.credentials import ISSHPrivateKey + + +sshKeyCheckerFactoryHelp = """ +This allows SSH public key authentication, based on public keys listed in +authorized_keys and authorized_keys2 files in user .ssh/ directories. +""" + + +try: + from twisted.conch.checkers import SSHPublicKeyDatabase + + class SSHKeyCheckerFactory(object): + """ + Generates checkers that will authenticate a SSH public key + """ + implements(ICheckerFactory, plugin.IPlugin) + authType = 'sshkey' + authHelp = sshKeyCheckerFactoryHelp + argStringFormat = 'No argstring required.' + credentialInterfaces = SSHPublicKeyDatabase.credentialInterfaces + + + def generateChecker(self, argstring=''): + """ + This checker factory ignores the argument string. Everything + needed to authenticate users is pulled out of the public keys + listed in user .ssh/ directories. + """ + return SSHPublicKeyDatabase() + + + + theSSHKeyCheckerFactory = SSHKeyCheckerFactory() + +except ImportError: + # if checkers can't be imported, then there should be no SSH cred plugin + pass diff -Nru twisted-12.0.0/twisted/plugins/twisted_core.py twisted-12.2.0/twisted/plugins/twisted_core.py --- twisted-12.0.0/twisted/plugins/twisted_core.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/plugins/twisted_core.py 2012-07-09 15:04:58.000000000 +0000 @@ -0,0 +1,9 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + + +from twisted.internet.endpoints import _SystemdParser, _TCP6ServerParser, _StandardIOParser + +systemdEndpointParser = _SystemdParser() +tcp6ServerEndpointParser = _TCP6ServerParser() +stdioEndpointParser = _StandardIOParser() diff -Nru twisted-12.0.0/twisted/plugins/twisted_reactors.py twisted-12.2.0/twisted/plugins/twisted_reactors.py --- twisted-12.0.0/twisted/plugins/twisted_reactors.py 2011-05-05 02:48:02.000000000 +0000 +++ twisted-12.2.0/twisted/plugins/twisted_reactors.py 2012-01-25 03:20:58.000000000 +0000 @@ -11,6 +11,10 @@ 'select', 'twisted.internet.selectreactor', 'select(2)-based reactor.') wx = Reactor( 'wx', 'twisted.internet.wxreactor', 'wxPython integration reactor.') +gi = Reactor( + 'gi', 'twisted.internet.gireactor', 'GObject Introspection integration reactor.') +gtk3 = Reactor( + 'gtk3', 'twisted.internet.gtk3reactor', 'Gtk3 integration reactor.') gtk = Reactor( 'gtk', 'twisted.internet.gtkreactor', 'Gtk1 integration reactor.') gtk2 = Reactor( diff -Nru twisted-12.0.0/twisted/protocols/amp.py twisted-12.2.0/twisted/protocols/amp.py --- twisted-12.0.0/twisted/protocols/amp.py 2011-09-23 12:30:19.000000000 +0000 +++ twisted-12.2.0/twisted/protocols/amp.py 2012-05-09 18:58:59.000000000 +0000 @@ -178,6 +178,7 @@ from cStringIO import StringIO from struct import pack import decimal, datetime +from itertools import count from zope.interface import Interface, implements @@ -187,6 +188,7 @@ from twisted.python.failure import Failure from twisted.python import log, filepath +from twisted.internet.interfaces import IFileDescriptorReceiver from twisted.internet.main import CONNECTION_LOST from twisted.internet.error import PeerVerifyError, ConnectionLost from twisted.internet.error import ConnectionClosed @@ -1473,6 +1475,74 @@ objects, self.subargs, Box(), proto ).serialize() for objects in inObject]) + + +class Descriptor(Integer): + """ + Encode and decode file descriptors for exchange over a UNIX domain socket. + + This argument type requires an AMP connection set up over an + L{IUNIXTransport} provider (for + example, the kind of connection created by + L{IReactorUNIX.connectUNIX} + and L{UNIXClientEndpoint}). + + There is no correspondence between the integer value of the file descriptor + on the sending and receiving sides, therefore an alternate approach is taken + to matching up received descriptors with particular L{Descriptor} + parameters. The argument is encoded to an ordinal (unique per connection) + for inclusion in the AMP command or response box. The descriptor itself is + sent using + L{IUNIXTransport.sendFileDescriptor}. + The receiver uses the order in which file descriptors are received and the + ordinal value to come up with the received copy of the descriptor. + """ + def fromStringProto(self, inString, proto): + """ + Take a unique identifier associated with a file descriptor which must + have been received by now and use it to look up that descriptor in a + dictionary where they are kept. + + @param inString: The base representation (as a byte string) of an + ordinal indicating which file descriptor corresponds to this usage + of this argument. + @type inString: C{str} + + @param proto: The protocol used to receive this descriptor. This + protocol must be connected via a transport providing + L{IUNIXTransport}. + @type proto: L{BinaryBoxProtocol} + + @return: The file descriptor represented by C{inString}. + @rtype: C{int} + """ + return proto._getDescriptor(int(inString)) + + + def toStringProto(self, inObject, proto): + """ + Send C{inObject}, an integer file descriptor, over C{proto}'s connection + and return a unique identifier which will allow the receiver to + associate the file descriptor with this argument. + + @param inObject: A file descriptor to duplicate over an AMP connection + as the value for this argument. + @type inObject: C{int} + + @param proto: The protocol which will be used to send this descriptor. + This protocol must be connected via a transport providing + L{IUNIXTransport}. + + @return: A byte string which can be used by the receiver to reconstruct + the file descriptor. + @type: C{str} + """ + identifier = proto._sendFileDescriptor(inObject) + outString = Integer.toStringProto(self, identifier, proto) + return outString + + + class Command: """ Subclass me to specify an AMP Command. @@ -1929,9 +1999,61 @@ -class BinaryBoxProtocol(StatefulStringProtocol, Int16StringReceiver): +class _DescriptorExchanger(object): + """ + L{_DescriptorExchanger} is a mixin for L{BinaryBoxProtocol} which adds + support for receiving file descriptors, a feature offered by + L{IUNIXTransport}. + + @ivar _descriptors: Temporary storage for all file descriptors received. + Values in this dictionary are the file descriptors (as integers). Keys + in this dictionary are ordinals giving the order in which each + descriptor was received. The ordering information is used to allow + L{Descriptor} to determine which is the correct descriptor for any + particular usage of that argument type. + @type _descriptors: C{dict} + + @ivar _sendingDescriptorCounter: A no-argument callable which returns the + ordinals, starting from 0. This is used to construct values for + C{_sendFileDescriptor}. + + @ivar _receivingDescriptorCounter: A no-argument callable which returns the + ordinals, starting from 0. This is used to construct values for + C{fileDescriptorReceived}. + """ + implements(IFileDescriptorReceiver) + + def __init__(self): + self._descriptors = {} + self._getDescriptor = self._descriptors.pop + self._sendingDescriptorCounter = count().next + self._receivingDescriptorCounter = count().next + + + def _sendFileDescriptor(self, descriptor): + """ + Assign and return the next ordinal to the given descriptor after sending + the descriptor over this protocol's transport. + """ + self.transport.sendFileDescriptor(descriptor) + return self._sendingDescriptorCounter() + + + def fileDescriptorReceived(self, descriptor): + """ + Collect received file descriptors to be claimed later by L{Descriptor}. + + @param descriptor: The received file descriptor. + @type descriptor: C{int} + """ + self._descriptors[self._receivingDescriptorCounter()] = descriptor + + + +class BinaryBoxProtocol(StatefulStringProtocol, Int16StringReceiver, + _DescriptorExchanger): """ - A protocol for receving L{Box}es - key/value pairs - via length-prefixed + A protocol for receiving L{AmpBox}es - key/value pairs - via length-prefixed strings. A box is composed of: - any number of key-value pairs, described by: @@ -1958,7 +2080,7 @@ than allowed by the protocol was received. @ivar boxReceiver: an L{IBoxReceiver} provider, whose L{ampBoxReceived} - method will be invoked for each L{Box} that is received. + method will be invoked for each L{AmpBox} that is received. """ implements(IBoxSender) @@ -1977,6 +2099,7 @@ innerProtocolClientFactory = None def __init__(self, boxReceiver): + _DescriptorExchanger.__init__(self) self.boxReceiver = boxReceiver diff -Nru twisted-12.0.0/twisted/protocols/ftp.py twisted-12.2.0/twisted/protocols/ftp.py --- twisted-12.0.0/twisted/protocols/ftp.py 2012-01-15 18:31:09.000000000 +0000 +++ twisted-12.2.0/twisted/protocols/ftp.py 2012-07-14 23:25:14.000000000 +0000 @@ -1068,6 +1068,8 @@ def ebSent(err): log.msg("Unexpected error attempting to transmit file to client:") log.err(err) + if err.check(FTPCmdError): + return err return (CNX_CLOSED_TXFR_ABORTED,) def cbOpened(file): diff -Nru twisted-12.0.0/twisted/protocols/htb.py twisted-12.2.0/twisted/protocols/htb.py --- twisted-12.0.0/twisted/protocols/htb.py 2012-01-17 02:37:22.000000000 +0000 +++ twisted-12.2.0/twisted/protocols/htb.py 2012-07-16 16:52:04.000000000 +0000 @@ -1,10 +1,10 @@ # -*- test-case-name: twisted.test.test_htb -*- -# # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. -"""Hierarchical Token Bucket traffic shaping. +""" +Hierarchical Token Bucket traffic shaping. Patterned after U{Martin Devera's Hierarchical Token Bucket traffic shaper for the Linux kernel}. @@ -13,13 +13,8 @@ } @seealso: U{Token Bucket Filter in Linux Advanced Routing & Traffic Control HOWTO} -@author: Kevin Turner """ -from __future__ import nested_scopes - -__version__ = '$Revision: 1.5 $'[11:-2] - # TODO: Investigate whether we should be using os.times()[-1] instead of # time.time. time.time, it has been pointed out, can go backwards. Is @@ -31,16 +26,19 @@ class Bucket: - """Token bucket, or something like it. + """ + Implementation of a Token bucket. - I can hold up to a certain number of tokens, and I drain over time. + A bucket can hold a certain number of tokens and it drains over time. - @cvar maxburst: Size of the bucket, in bytes. If None, the bucket is - never full. - @type maxburst: int - @cvar rate: Rate the bucket drains, in bytes per second. If None, - the bucket drains instantaneously. - @type rate: int + @cvar maxburst: The maximum number of tokens that the bucket can + hold at any given time. If this is C{None}, the bucket has + an infinite size. + @type maxburst: C{int} + @cvar rate: The rate at which the bucket drains, in number + of tokens per second. If the rate is C{None}, the bucket + drains instantaneously. + @type rate: C{int} """ maxburst = None @@ -49,18 +47,31 @@ _refcount = 0 def __init__(self, parentBucket=None): + """ + Create a L{Bucket} that may have a parent L{Bucket}. + + @param parentBucket: If a parent Bucket is specified, + all L{add} and L{drip} operations on this L{Bucket} + will be applied on the parent L{Bucket} as well. + @type parentBucket: L{Bucket} + """ self.content = 0 - self.parentBucket=parentBucket + self.parentBucket = parentBucket self.lastDrip = time() + def add(self, amount): - """Add tokens to me. + """ + Adds tokens to the L{Bucket} and its C{parentBucket}. - @param amount: A quanity of tokens to add. - @type amount: int + This will add as many of the C{amount} tokens as will fit into both + this L{Bucket} and its C{parentBucket}. - @returns: The number of tokens that fit. - @returntype: int + @param amount: The number of tokens to try to add. + @type amount: C{int} + + @returns: The number of tokens that actually fit. + @returntype: C{int} """ self.drip() if self.maxburst is None: @@ -73,15 +84,16 @@ self.content += allowable return allowable + def drip(self): """ Let some of the bucket drain. - How much of the bucket drains depends on how long it has been - since I was last called. + The L{Bucket} drains at the rate specified by the class + variable C{rate}. @returns: C{True} if the bucket is empty after this drip. - @returntype: bool + @returntype: C{bool} """ if self.parentBucket is not None: self.parentBucket.drip() @@ -90,26 +102,29 @@ self.content = 0 else: now = time() - deltaT = now - self.lastDrip - self.content = long(max(0, self.content - deltaT * self.rate)) + deltaTime = now - self.lastDrip + deltaTokens = deltaTime * self.rate + self.content = max(0, self.content - deltaTokens) self.lastDrip = now return self.content == 0 class IBucketFilter(Interface): def getBucketFor(*somethings, **some_kw): - """I'll give you a bucket for something. + """ + Return a L{Bucket} corresponding to the provided parameters. @returntype: L{Bucket} """ class HierarchicalBucketFilter: - """I filter things into buckets, and I am nestable. + """ + Filter things into buckets that can be nested. @cvar bucketFactory: Class of buckets to make. - @type bucketFactory: L{Bucket} class + @type bucketFactory: L{Bucket} @cvar sweepInterval: Seconds between sweeping out the bucket cache. - @type sweepInterval: int + @type sweepInterval: C{int} """ implements(IBucketFilter) @@ -123,7 +138,8 @@ self.lastSweep = time() def getBucketFor(self, *a, **kw): - """You want a bucket for that? I'll give you a bucket. + """ + Find or create a L{Bucket} corresponding to the provided parameters. Any parameters are passed on to L{getBucketKey}, from them it decides which bucket you get. @@ -147,25 +163,31 @@ return bucket def getBucketKey(self, *a, **kw): - """I determine who gets which bucket. + """ + Construct a key based on the input parameters to choose a L{Bucket}. - Unless I'm overridden, everything gets the same bucket. + The default implementation returns the same key for all + arguments. Override this method to provide L{Bucket} selection. - @returns: something to be used as a key in the bucket cache. + @returns: Something to be used as a key in the bucket cache. """ return None def sweep(self): - """I throw away references to empty buckets.""" + """ + Remove empty buckets. + """ for key, bucket in self.buckets.items(): - if (bucket._refcount == 0) and bucket.drip(): + bucket_is_empty = bucket.drip() + if (bucket._refcount == 0) and bucket_is_empty: del self.buckets[key] self.lastSweep = time() class FilterByHost(HierarchicalBucketFilter): - """A bucket filter with a bucket for each host. + """ + A Hierarchical Bucket filter with a L{Bucket} for each host. """ sweepInterval = 60 * 20 @@ -174,7 +196,8 @@ class FilterByServer(HierarchicalBucketFilter): - """A bucket filter with a bucket for each service. + """ + A Hierarchical Bucket filter with a L{Bucket} for each service. """ sweepInterval = None @@ -183,7 +206,8 @@ class ShapedConsumer(pcp.ProducerConsumerProxy): - """I wrap a Consumer and shape the rate at which it receives data. + """ + Wraps a C{Consumer} and shapes the rate at which it receives data. """ # Providing a Pull interface means I don't have to try to schedule # traffic with callLaters. @@ -208,12 +232,13 @@ class ShapedTransport(ShapedConsumer): - """I wrap a Transport and shape the rate at which it receives data. + """ + Wraps a C{Transport} and shapes the rate at which it receives data. - I am a L{ShapedConsumer} with a little bit of magic to provide for - the case where the consumer I wrap is also a Transport and people - will be attempting to access attributes I do not proxy as a - Consumer (e.g. loseConnection). + This is a L{ShapedConsumer} with a little bit of magic to provide for + the case where the consumer it wraps is also a C{Transport} and people + will be attempting to access attributes this does not proxy as a + C{Consumer} (e.g. C{loseConnection}). """ # Ugh. We only wanted to filter IConsumer, not ITransport. @@ -225,7 +250,8 @@ class ShapedProtocolFactory: - """I dispense Protocols with traffic shaping on their transports. + """ + Dispense C{Protocols} with traffic shaping on their transports. Usage:: @@ -233,13 +259,14 @@ myserver.protocol = ShapedProtocolFactory(myserver.protocol, bucketFilter) - Where SomeServerFactory is a L{twisted.internet.protocol.Factory}, and - bucketFilter is an instance of L{HierarchicalBucketFilter}. + Where C{SomeServerFactory} is a L{twisted.internet.protocol.Factory}, and + C{bucketFilter} is an instance of L{HierarchicalBucketFilter}. """ def __init__(self, protoClass, bucketFilter): - """Tell me what to wrap and where to get buckets. + """ + Tell me what to wrap and where to get buckets. - @param protoClass: The class of Protocol I will generate + @param protoClass: The class of C{Protocol} this will generate wrapped instances of. @type protoClass: L{Protocol} class @@ -253,11 +280,12 @@ self.bucketFilter = bucketFilter def __call__(self, *a, **kw): - """Make a Protocol instance with a shaped transport. + """ + Make a C{Protocol} instance with a shaped transport. Any parameters will be passed on to the protocol's initializer. - @returns: a Protocol instance with a L{ShapedTransport}. + @returns: A C{Protocol} instance with a L{ShapedTransport}. """ proto = self.protocol(*a, **kw) origMakeConnection = proto.makeConnection diff -Nru twisted-12.0.0/twisted/protocols/ident.py twisted-12.2.0/twisted/protocols/ident.py --- twisted-12.0.0/twisted/protocols/ident.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/protocols/ident.py 2012-05-31 17:58:56.000000000 +0000 @@ -4,12 +4,8 @@ """ Ident protocol implementation. - -@author: Jean-Paul Calderone """ -from __future__ import generators - import struct from twisted.internet import defer diff -Nru twisted-12.0.0/twisted/protocols/sip.py twisted-12.2.0/twisted/protocols/sip.py --- twisted-12.0.0/twisted/protocols/sip.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/protocols/sip.py 2012-06-07 13:15:27.000000000 +0000 @@ -632,6 +632,7 @@ self.length = None # body length self.bodyReceived = 0 # how much of the body we received self.message = None + self.header = None self.setLineMode(remainingData) def invalidMessage(self): @@ -699,24 +700,36 @@ else: assert self.state == "headers" if line: - # XXX support multi-line headers - try: - name, value = line.split(":", 1) - except ValueError: - self.invalidMessage() - return - self.message.addHeader(name, value.lstrip()) - if name.lower() == "content-length": + # multiline header + if line.startswith(" ") or line.startswith("\t"): + name, value = self.header + self.header = name, (value + line.lstrip()) + else: + # new header + if self.header: + self.message.addHeader(*self.header) + self.header = None try: - self.length = int(value.lstrip()) + name, value = line.split(":", 1) except ValueError: self.invalidMessage() return + self.header = name, value.lstrip() + # XXX we assume content-length won't be multiline + if name.lower() == "content-length": + try: + self.length = int(value.lstrip()) + except ValueError: + self.invalidMessage() + return else: # CRLF, we now have message body until self.length bytes, # or if no length was given, until there is no more data # from the connection sending us data. self.state = "body" + if self.header: + self.message.addHeader(*self.header) + self.header = None if self.length == 0: self.messageDone() return @@ -1289,7 +1302,7 @@ def getAddress(self, userURI): if userURI.host != self.domain: return defer.fail(LookupError("unknown domain")) - if self.users.has_key(userURI.username): + if userURI.username in self.users: dc, url = self.users[userURI.username] return defer.succeed(url) else: @@ -1321,7 +1334,7 @@ if logicalURL.host != self.domain: log.msg("Registration for domain we don't handle.") return defer.fail(RegistrationError(404)) - if self.users.has_key(logicalURL.username): + if logicalURL.username in self.users: dc, old = self.users[logicalURL.username] dc.reset(3600) else: diff -Nru twisted-12.0.0/twisted/protocols/test/test_tls.py twisted-12.2.0/twisted/protocols/test/test_tls.py --- twisted-12.0.0/twisted/protocols/test/test_tls.py 2012-01-22 16:03:52.000000000 +0000 +++ twisted-12.2.0/twisted/protocols/test/test_tls.py 2012-08-17 20:22:18.000000000 +0000 @@ -6,6 +6,7 @@ """ from zope.interface.verify import verifyObject +from zope.interface import Interface, directlyProvides try: from twisted.protocols.tls import TLSMemoryBIOProtocol, TLSMemoryBIOFactory @@ -208,6 +209,30 @@ self.assertTrue(ISystemHandle.providedBy(proto)) + def test_wrappedProtocolInterfaces(self): + """ + L{TLSMemoryBIOProtocol} instances provide the interfaces provided by + the transport they wrap. + """ + class ITransport(Interface): + pass + + class MyTransport(object): + def write(self, bytes): + pass + + clientFactory = ClientFactory() + contextFactory = ClientContextFactory() + wrapperFactory = TLSMemoryBIOFactory( + contextFactory, True, clientFactory) + + transport = MyTransport() + directlyProvides(transport, ITransport) + tlsProtocol = TLSMemoryBIOProtocol(wrapperFactory, Protocol()) + tlsProtocol.makeConnection(transport) + self.assertTrue(ITransport.providedBy(tlsProtocol)) + + def test_getHandle(self): """ L{TLSMemoryBIOProtocol.getHandle} returns the L{OpenSSL.SSL.Connection} diff -Nru twisted-12.0.0/twisted/protocols/tls.py twisted-12.2.0/twisted/protocols/tls.py --- twisted-12.0.0/twisted/protocols/tls.py 2012-01-22 16:03:52.000000000 +0000 +++ twisted-12.2.0/twisted/protocols/tls.py 2012-08-17 20:22:18.000000000 +0000 @@ -46,7 +46,7 @@ raise raise ImportError("twisted.protocols.tls requires pyOpenSSL 0.10 or newer.") -from zope.interface import implements +from zope.interface import implements, providedBy, directlyProvides from twisted.python.failure import Failure from twisted.python import log @@ -298,6 +298,10 @@ self._tlsConnection.set_accept_state() self._appSendBuffer = [] + # Add interfaces provided by the transport we are wrapping: + for interface in providedBy(transport): + directlyProvides(self, interface) + # Intentionally skip ProtocolWrapper.makeConnection - it might call # wrappedProtocol.makeConnection, which we want to make conditional. Protocol.makeConnection(self, transport) diff -Nru twisted-12.0.0/twisted/python/_epoll.c twisted-12.2.0/twisted/python/_epoll.c --- twisted-12.0.0/twisted/python/_epoll.c 2011-03-14 17:51:06.000000000 +0000 +++ twisted-12.2.0/twisted/python/_epoll.c 2012-02-19 19:24:21.000000000 +0000 @@ -1,4 +1,4 @@ -/* Generated by Cython 0.14.1 on Tue Mar 8 19:42:56 2011 */ +/* Generated by Cython 0.15.1 on Fri Feb 17 23:33:28 2012 */ #define PY_SSIZE_T_CLEAN #include "Python.h" @@ -46,7 +46,7 @@ #define PY_SSIZE_T_MIN INT_MIN #define PY_FORMAT_SIZE_T "" #define PyInt_FromSsize_t(z) PyInt_FromLong(z) - #define PyInt_AsSsize_t(o) PyInt_AsLong(o) + #define PyInt_AsSsize_t(o) __Pyx_PyInt_AsInt(o) #define PyNumber_Index(o) PyNumber_Int(o) #define PyIndex_Check(o) PyNumber_Check(o) #define PyErr_WarnEx(category, message, stacklevel) PyErr_Warn(category, message) @@ -159,6 +159,15 @@ #define PyBoolObject PyLongObject #endif +#if PY_VERSION_HEX < 0x03020000 + typedef long Py_hash_t; + #define __Pyx_PyInt_FromHash_t PyInt_FromLong + #define __Pyx_PyInt_AsHash_t PyInt_AsLong +#else + #define __Pyx_PyInt_FromHash_t PyInt_FromSsize_t + #define __Pyx_PyInt_AsHash_t PyInt_AsSsize_t +#endif + #if PY_MAJOR_VERSION >= 3 #define __Pyx_PyNumber_Divide(x,y) PyNumber_TrueDivide(x,y) @@ -209,22 +218,28 @@ #define __Pyx_DOCSTR(n) (n) #endif -#ifdef __cplusplus -#define __PYX_EXTERN_C extern "C" -#else -#define __PYX_EXTERN_C extern +#ifndef __PYX_EXTERN_C + #ifdef __cplusplus + #define __PYX_EXTERN_C extern "C" + #else + #define __PYX_EXTERN_C extern + #endif #endif #if defined(WIN32) || defined(MS_WINDOWS) #define _USE_MATH_DEFINES #endif #include +#define __PYX_HAVE__twisted__python___epoll #define __PYX_HAVE_API__twisted__python___epoll #include "stdio.h" #include "errno.h" #include "string.h" #include "stdint.h" #include "sys/epoll.h" +#ifdef _OPENMP +#include +#endif /* _OPENMP */ #ifdef PYREX_WITHOUT_ASSERTIONS #define CYTHON_WITHOUT_ASSERTIONS @@ -267,6 +282,7 @@ #define __Pyx_PyBytes_FromUString(s) PyBytes_FromString((char*)s) #define __Pyx_PyBytes_AsUString(s) ((unsigned char*) PyBytes_AsString(s)) +#define __Pyx_Owned_Py_None(b) (Py_INCREF(Py_None), Py_None) #define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False)) static CYTHON_INLINE int __Pyx_PyObject_IsTrue(PyObject*); static CYTHON_INLINE PyObject* __Pyx_PyNumber_Int(PyObject* x); @@ -279,17 +295,17 @@ #ifdef __GNUC__ -/* Test for GCC > 2.95 */ -#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) -#define likely(x) __builtin_expect(!!(x), 1) -#define unlikely(x) __builtin_expect(!!(x), 0) -#else /* __GNUC__ > 2 ... */ -#define likely(x) (x) -#define unlikely(x) (x) -#endif /* __GNUC__ > 2 ... */ + /* Test for GCC > 2.95 */ + #if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) + #define likely(x) __builtin_expect(!!(x), 1) + #define unlikely(x) __builtin_expect(!!(x), 0) + #else /* __GNUC__ > 2 ... */ + #define likely(x) (x) + #define unlikely(x) (x) + #endif /* __GNUC__ > 2 ... */ #else /* __GNUC__ */ -#define likely(x) (x) -#define unlikely(x) (x) + #define likely(x) (x) + #define unlikely(x) (x) #endif /* __GNUC__ */ static PyObject *__pyx_m; @@ -306,22 +322,23 @@ "_epoll.pyx", }; -/* Type declarations */ +/*--- Type declarations ---*/ +struct __pyx_obj_7twisted_6python_6_epoll_epoll; -/* "twisted/python/_epoll.pyx":68 - * cdef extern void PyEval_RestoreThread(PyThreadState*) +/* "twisted/python/_epoll.pyx":106 + * free(events) * * cdef class epoll: # <<<<<<<<<<<<<< * """ * Represent a set of file descriptors being monitored for events. */ - struct __pyx_obj_7twisted_6python_6_epoll_epoll { PyObject_HEAD int fd; int initialized; }; + #ifndef CYTHON_REFNANNY #define CYTHON_REFNANNY 0 #endif @@ -336,40 +353,39 @@ void (*FinishContext)(void**); } __Pyx_RefNannyAPIStruct; static __Pyx_RefNannyAPIStruct *__Pyx_RefNanny = NULL; - static __Pyx_RefNannyAPIStruct * __Pyx_RefNannyImportAPI(const char *modname) { - PyObject *m = NULL, *p = NULL; - void *r = NULL; - m = PyImport_ImportModule((char *)modname); - if (!m) goto end; - p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); - if (!p) goto end; - r = PyLong_AsVoidPtr(p); - end: - Py_XDECREF(p); - Py_XDECREF(m); - return (__Pyx_RefNannyAPIStruct *)r; - } - #define __Pyx_RefNannySetupContext(name) void *__pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) + static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname); /*proto*/ + #define __Pyx_RefNannyDeclarations void *__pyx_refnanny = NULL; + #define __Pyx_RefNannySetupContext(name) __pyx_refnanny = __Pyx_RefNanny->SetupContext((name), __LINE__, __FILE__) #define __Pyx_RefNannyFinishContext() __Pyx_RefNanny->FinishContext(&__pyx_refnanny) - #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_INCREF(r) __Pyx_RefNanny->INCREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_DECREF(r) __Pyx_RefNanny->DECREF(__pyx_refnanny, (PyObject *)(r), __LINE__) + #define __Pyx_GOTREF(r) __Pyx_RefNanny->GOTREF(__pyx_refnanny, (PyObject *)(r), __LINE__) #define __Pyx_GIVEREF(r) __Pyx_RefNanny->GIVEREF(__pyx_refnanny, (PyObject *)(r), __LINE__) - #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r);} } while(0) + #define __Pyx_XINCREF(r) do { if((r) != NULL) {__Pyx_INCREF(r); }} while(0) + #define __Pyx_XDECREF(r) do { if((r) != NULL) {__Pyx_DECREF(r); }} while(0) + #define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r); }} while(0) + #define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);}} while(0) #else + #define __Pyx_RefNannyDeclarations #define __Pyx_RefNannySetupContext(name) #define __Pyx_RefNannyFinishContext() #define __Pyx_INCREF(r) Py_INCREF(r) #define __Pyx_DECREF(r) Py_DECREF(r) #define __Pyx_GOTREF(r) #define __Pyx_GIVEREF(r) + #define __Pyx_XINCREF(r) Py_XINCREF(r) #define __Pyx_XDECREF(r) Py_XDECREF(r) + #define __Pyx_XGOTREF(r) + #define __Pyx_XGIVEREF(r) #endif /* CYTHON_REFNANNY */ -#define __Pyx_XGIVEREF(r) do { if((r) != NULL) {__Pyx_GIVEREF(r);} } while(0) -#define __Pyx_XGOTREF(r) do { if((r) != NULL) {__Pyx_GOTREF(r);} } while(0) static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/ +static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ +static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ + +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause); /*proto*/ + static void __Pyx_RaiseDoubleKeywordsError( const char* func_name, PyObject* kw_name); /*proto*/ @@ -378,11 +394,6 @@ static void __Pyx_RaiseArgtupleInvalid(const char* func_name, int exact, Py_ssize_t num_min, Py_ssize_t num_max, Py_ssize_t num_found); /*proto*/ -static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ -static CYTHON_INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **tb); /*proto*/ - -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/ - static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject *); static CYTHON_INLINE unsigned short __Pyx_PyInt_AsUnsignedShort(PyObject *); @@ -415,16 +426,20 @@ static CYTHON_INLINE signed PY_LONG_LONG __Pyx_PyInt_AsSignedLongLong(PyObject *); -static void __Pyx_AddTraceback(const char *funcname); /*proto*/ +static int __Pyx_check_binary_version(void); + +static void __Pyx_AddTraceback(const char *funcname, int __pyx_clineno, + int __pyx_lineno, const char *__pyx_filename); /*proto*/ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/ -/* Module declarations from twisted.python._epoll */ +/* Module declarations from 'twisted.python._epoll' */ static PyTypeObject *__pyx_ptype_7twisted_6python_6_epoll_epoll = 0; +static PyObject *__pyx_f_7twisted_6python_6_epoll_call_epoll_wait(int, unsigned int, int); /*proto*/ #define __Pyx_MODULE_NAME "twisted.python._epoll" -static int __pyx_module_is_main_twisted__python___epoll = 0; +int __pyx_module_is_main_twisted__python___epoll = 0; -/* Implementation of twisted.python._epoll */ +/* Implementation of 'twisted.python._epoll' */ static PyObject *__pyx_builtin_IOError; static char __pyx_k_1[] = "\nInterface to epoll I/O event notification facility.\n"; static char __pyx_k__ET[] = "ET"; @@ -436,26 +451,45 @@ static char __pyx_k__MSG[] = "MSG"; static char __pyx_k__OUT[] = "OUT"; static char __pyx_k__PRI[] = "PRI"; -static char __pyx_k__data[] = "data"; static char __pyx_k__size[] = "size"; static char __pyx_k__RDBAND[] = "RDBAND"; static char __pyx_k__RDNORM[] = "RDNORM"; static char __pyx_k__WRBAND[] = "WRBAND"; static char __pyx_k__WRNORM[] = "WRNORM"; -static char __pyx_k__append[] = "append"; static char __pyx_k__events[] = "events"; static char __pyx_k__CTL_ADD[] = "CTL_ADD"; static char __pyx_k__CTL_DEL[] = "CTL_DEL"; static char __pyx_k__CTL_MOD[] = "CTL_MOD"; +static char __pyx_k__EPOLLET[] = "EPOLLET"; +static char __pyx_k__EPOLLIN[] = "EPOLLIN"; static char __pyx_k__IOError[] = "IOError"; static char __pyx_k__timeout[] = "timeout"; +static char __pyx_k__EPOLLERR[] = "EPOLLERR"; +static char __pyx_k__EPOLLHUP[] = "EPOLLHUP"; +static char __pyx_k__EPOLLMSG[] = "EPOLLMSG"; +static char __pyx_k__EPOLLOUT[] = "EPOLLOUT"; +static char __pyx_k__EPOLLPRI[] = "EPOLLPRI"; static char __pyx_k____main__[] = "__main__"; static char __pyx_k____test__[] = "__test__"; static char __pyx_k__maxevents[] = "maxevents"; -static char __pyx_k__initialized[] = "initialized"; +static char __pyx_k__EPOLLRDBAND[] = "EPOLLRDBAND"; +static char __pyx_k__EPOLLRDNORM[] = "EPOLLRDNORM"; +static char __pyx_k__EPOLLWRBAND[] = "EPOLLWRBAND"; +static char __pyx_k__EPOLLWRNORM[] = "EPOLLWRNORM"; static PyObject *__pyx_n_s__CTL_ADD; static PyObject *__pyx_n_s__CTL_DEL; static PyObject *__pyx_n_s__CTL_MOD; +static PyObject *__pyx_n_s__EPOLLERR; +static PyObject *__pyx_n_s__EPOLLET; +static PyObject *__pyx_n_s__EPOLLHUP; +static PyObject *__pyx_n_s__EPOLLIN; +static PyObject *__pyx_n_s__EPOLLMSG; +static PyObject *__pyx_n_s__EPOLLOUT; +static PyObject *__pyx_n_s__EPOLLPRI; +static PyObject *__pyx_n_s__EPOLLRDBAND; +static PyObject *__pyx_n_s__EPOLLRDNORM; +static PyObject *__pyx_n_s__EPOLLWRBAND; +static PyObject *__pyx_n_s__EPOLLWRNORM; static PyObject *__pyx_n_s__ERR; static PyObject *__pyx_n_s__ET; static PyObject *__pyx_n_s__HUP; @@ -470,77 +504,335 @@ static PyObject *__pyx_n_s__WRNORM; static PyObject *__pyx_n_s____main__; static PyObject *__pyx_n_s____test__; -static PyObject *__pyx_n_s__append; -static PyObject *__pyx_n_s__data; static PyObject *__pyx_n_s__events; static PyObject *__pyx_n_s__fd; -static PyObject *__pyx_n_s__initialized; static PyObject *__pyx_n_s__maxevents; static PyObject *__pyx_n_s__op; static PyObject *__pyx_n_s__size; static PyObject *__pyx_n_s__timeout; -/* "twisted/python/_epoll.pyx":76 +/* "twisted/python/_epoll.pyx":68 + * cdef extern void PyEval_RestoreThread(PyThreadState*) + * + * cdef call_epoll_wait(int fd, unsigned int maxevents, int timeout_msec): # <<<<<<<<<<<<<< + * """ + * Wait for an I/O event, wrap epoll_wait(2). + */ + +static PyObject *__pyx_f_7twisted_6python_6_epoll_call_epoll_wait(int __pyx_v_fd, unsigned int __pyx_v_maxevents, int __pyx_v_timeout_msec) { + struct epoll_event *__pyx_v_events; + int __pyx_v_result; + int __pyx_v_nbytes; + PyThreadState *__pyx_v__save; + PyObject *__pyx_v_results = NULL; + long __pyx_v_i; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_t_5; + int __pyx_t_6; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("call_epoll_wait"); + + /* "twisted/python/_epoll.pyx":89 + * cdef PyThreadState *_save + * + * nbytes = sizeof(epoll_event) * maxevents # <<<<<<<<<<<<<< + * events = malloc(nbytes) + * memset(events, 0, nbytes) + */ + __pyx_v_nbytes = ((sizeof(struct epoll_event)) * __pyx_v_maxevents); + + /* "twisted/python/_epoll.pyx":90 + * + * nbytes = sizeof(epoll_event) * maxevents + * events = malloc(nbytes) # <<<<<<<<<<<<<< + * memset(events, 0, nbytes) + * try: + */ + __pyx_v_events = ((struct epoll_event *)malloc(__pyx_v_nbytes)); + + /* "twisted/python/_epoll.pyx":91 + * nbytes = sizeof(epoll_event) * maxevents + * events = malloc(nbytes) + * memset(events, 0, nbytes) # <<<<<<<<<<<<<< + * try: + * _save = PyEval_SaveThread() + */ + memset(__pyx_v_events, 0, __pyx_v_nbytes); + + /* "twisted/python/_epoll.pyx":92 + * events = malloc(nbytes) + * memset(events, 0, nbytes) + * try: # <<<<<<<<<<<<<< + * _save = PyEval_SaveThread() + * result = epoll_wait(fd, events, maxevents, timeout_msec) + */ + /*try:*/ { + + /* "twisted/python/_epoll.pyx":93 + * memset(events, 0, nbytes) + * try: + * _save = PyEval_SaveThread() # <<<<<<<<<<<<<< + * result = epoll_wait(fd, events, maxevents, timeout_msec) + * PyEval_RestoreThread(_save) + */ + __pyx_v__save = PyEval_SaveThread(); + + /* "twisted/python/_epoll.pyx":94 + * try: + * _save = PyEval_SaveThread() + * result = epoll_wait(fd, events, maxevents, timeout_msec) # <<<<<<<<<<<<<< + * PyEval_RestoreThread(_save) + * + */ + __pyx_v_result = epoll_wait(__pyx_v_fd, __pyx_v_events, __pyx_v_maxevents, __pyx_v_timeout_msec); + + /* "twisted/python/_epoll.pyx":95 + * _save = PyEval_SaveThread() + * result = epoll_wait(fd, events, maxevents, timeout_msec) + * PyEval_RestoreThread(_save) # <<<<<<<<<<<<<< + * + * if result == -1: + */ + PyEval_RestoreThread(__pyx_v__save); + + /* "twisted/python/_epoll.pyx":97 + * PyEval_RestoreThread(_save) + * + * if result == -1: # <<<<<<<<<<<<<< + * raise IOError(errno, strerror(errno)) + * results = [] + */ + __pyx_t_1 = (__pyx_v_result == -1); + if (__pyx_t_1) { + + /* "twisted/python/_epoll.pyx":98 + * + * if result == -1: + * raise IOError(errno, strerror(errno)) # <<<<<<<<<<<<<< + * results = [] + * for i from 0 <= i < result: + */ + __pyx_t_2 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_GOTREF(((PyObject *)__pyx_t_3)); + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_GOTREF(((PyObject *)__pyx_t_4)); + PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_4, 1, ((PyObject *)__pyx_t_3)); + __Pyx_GIVEREF(((PyObject *)__pyx_t_3)); + __pyx_t_2 = 0; + __pyx_t_3 = 0; + __pyx_t_3 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L4;} + goto __pyx_L6; + } + __pyx_L6:; + + /* "twisted/python/_epoll.pyx":99 + * if result == -1: + * raise IOError(errno, strerror(errno)) + * results = [] # <<<<<<<<<<<<<< + * for i from 0 <= i < result: + * results.append((events[i].data.fd, events[i].events)) + */ + __pyx_t_3 = PyList_New(0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 99; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_GOTREF(((PyObject *)__pyx_t_3)); + __pyx_v_results = __pyx_t_3; + __pyx_t_3 = 0; + + /* "twisted/python/_epoll.pyx":100 + * raise IOError(errno, strerror(errno)) + * results = [] + * for i from 0 <= i < result: # <<<<<<<<<<<<<< + * results.append((events[i].data.fd, events[i].events)) + * return results + */ + __pyx_t_5 = __pyx_v_result; + for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_5; __pyx_v_i++) { + + /* "twisted/python/_epoll.pyx":101 + * results = [] + * for i from 0 <= i < result: + * results.append((events[i].data.fd, events[i].events)) # <<<<<<<<<<<<<< + * return results + * finally: + */ + if (unlikely(((PyObject *)__pyx_v_results) == Py_None)) { + PyErr_Format(PyExc_AttributeError, "'NoneType' object has no attribute '%s'", "append"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L4;} + } + __pyx_t_3 = PyInt_FromLong((__pyx_v_events[__pyx_v_i]).data.fd); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_GOTREF(__pyx_t_3); + __pyx_t_4 = PyInt_FromLong(((int)(__pyx_v_events[__pyx_v_i]).events)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_GOTREF(__pyx_t_4); + __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_GOTREF(((PyObject *)__pyx_t_2)); + PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); + __Pyx_GIVEREF(__pyx_t_3); + PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_4); + __Pyx_GIVEREF(__pyx_t_4); + __pyx_t_3 = 0; + __pyx_t_4 = 0; + __pyx_t_6 = PyList_Append(__pyx_v_results, ((PyObject *)__pyx_t_2)); if (unlikely(__pyx_t_6 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 101; __pyx_clineno = __LINE__; goto __pyx_L4;} + __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; + } + + /* "twisted/python/_epoll.pyx":102 + * for i from 0 <= i < result: + * results.append((events[i].data.fd, events[i].events)) + * return results # <<<<<<<<<<<<<< + * finally: + * free(events) + */ + __Pyx_XDECREF(__pyx_r); + __Pyx_INCREF(((PyObject *)__pyx_v_results)); + __pyx_r = ((PyObject *)__pyx_v_results); + goto __pyx_L3; + } + + /* "twisted/python/_epoll.pyx":104 + * return results + * finally: + * free(events) # <<<<<<<<<<<<<< + * + * cdef class epoll: + */ + /*finally:*/ { + int __pyx_why; + PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb; + int __pyx_exc_lineno; + __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0; + __pyx_why = 0; goto __pyx_L5; + __pyx_L3: __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0; + __pyx_why = 3; goto __pyx_L5; + __pyx_L4: { + __pyx_why = 4; + __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; + __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; + __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; + __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb); + __pyx_exc_lineno = __pyx_lineno; + goto __pyx_L5; + } + __pyx_L5:; + free(__pyx_v_events); + switch (__pyx_why) { + case 3: goto __pyx_L0; + case 4: { + __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb); + __pyx_lineno = __pyx_exc_lineno; + __pyx_exc_type = 0; + __pyx_exc_value = 0; + __pyx_exc_tb = 0; + goto __pyx_L1_error; + } + } + } + + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("twisted.python._epoll.call_epoll_wait", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = 0; + __pyx_L0:; + __Pyx_XDECREF(__pyx_v_results); + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "twisted/python/_epoll.pyx":114 * cdef int initialized * - * def __init__(self, int size): # <<<<<<<<<<<<<< - * self.fd = epoll_create(size) - * if self.fd == -1: + * def __init__(self, int size=1023): # <<<<<<<<<<<<<< + * """ + * The constructor arguments are compatible with select.poll.__init__. */ static int __pyx_pf_7twisted_6python_6_epoll_5epoll___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_7twisted_6python_6_epoll_5epoll___init__[] = "\n The constructor arguments are compatible with select.poll.__init__.\n "; +struct wrapperbase __pyx_wrapperbase_7twisted_6python_6_epoll_5epoll___init__; static int __pyx_pf_7twisted_6python_6_epoll_5epoll___init__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { int __pyx_v_size; int __pyx_r; + __Pyx_RefNannyDeclarations int __pyx_t_1; PyObject *__pyx_t_2 = NULL; PyObject *__pyx_t_3 = NULL; PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__size,0}; __Pyx_RefNannySetupContext("__init__"); - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); + { PyObject* values[1] = {0}; - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 0: - values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__size); - if (likely(values[0])) kw_args--; - else goto __pyx_L5_argtuple_error; - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - __pyx_v_size = __Pyx_PyInt_AsInt(values[0]); if (unlikely((__pyx_v_size == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } else if (PyTuple_GET_SIZE(__pyx_args) != 1) { - goto __pyx_L5_argtuple_error; - } else { - __pyx_v_size = __Pyx_PyInt_AsInt(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_size == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 0: + if (kw_args > 0) { + PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__size); + if (value) { values[0] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "__init__") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 114; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + } + if (values[0]) { + __pyx_v_size = __Pyx_PyInt_AsInt(values[0]); if (unlikely((__pyx_v_size == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 114; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } else { + __pyx_v_size = ((int)1023); + } } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("__init__", 1, 1, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 76; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("__init__", 0, 0, 1, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 114; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; - __Pyx_AddTraceback("twisted.python._epoll.epoll.__init__"); + __Pyx_AddTraceback("twisted.python._epoll.epoll.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return -1; __pyx_L4_argument_unpacking_done:; - /* "twisted/python/_epoll.pyx":77 - * - * def __init__(self, int size): + /* "twisted/python/_epoll.pyx":118 + * The constructor arguments are compatible with select.poll.__init__. + * """ * self.fd = epoll_create(size) # <<<<<<<<<<<<<< * if self.fd == -1: * raise IOError(errno, strerror(errno)) */ ((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd = epoll_create(__pyx_v_size); - /* "twisted/python/_epoll.pyx":78 - * def __init__(self, int size): + /* "twisted/python/_epoll.pyx":119 + * """ * self.fd = epoll_create(size) * if self.fd == -1: # <<<<<<<<<<<<<< * raise IOError(errno, strerror(errno)) @@ -549,18 +841,18 @@ __pyx_t_1 = (((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd == -1); if (__pyx_t_1) { - /* "twisted/python/_epoll.pyx":79 + /* "twisted/python/_epoll.pyx":120 * self.fd = epoll_create(size) * if self.fd == -1: * raise IOError(errno, strerror(errno)) # <<<<<<<<<<<<<< * self.initialized = 1 * */ - __pyx_t_2 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_3)); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); @@ -568,17 +860,17 @@ __Pyx_GIVEREF(((PyObject *)__pyx_t_3)); __pyx_t_2 = 0; __pyx_t_3 = 0; - __pyx_t_3 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; - __Pyx_Raise(__pyx_t_3, 0, 0); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; - /* "twisted/python/_epoll.pyx":80 + /* "twisted/python/_epoll.pyx":121 * if self.fd == -1: * raise IOError(errno, strerror(errno)) * self.initialized = 1 # <<<<<<<<<<<<<< @@ -593,14 +885,14 @@ __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); __Pyx_XDECREF(__pyx_t_4); - __Pyx_AddTraceback("twisted.python._epoll.epoll.__init__"); + __Pyx_AddTraceback("twisted.python._epoll.epoll.__init__", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = -1; __pyx_L0:; __Pyx_RefNannyFinishContext(); return __pyx_r; } -/* "twisted/python/_epoll.pyx":82 +/* "twisted/python/_epoll.pyx":123 * self.initialized = 1 * * def __dealloc__(self): # <<<<<<<<<<<<<< @@ -610,9 +902,10 @@ static void __pyx_pf_7twisted_6python_6_epoll_5epoll_1__dealloc__(PyObject *__pyx_v_self); /*proto*/ static void __pyx_pf_7twisted_6python_6_epoll_5epoll_1__dealloc__(PyObject *__pyx_v_self) { + __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("__dealloc__"); - /* "twisted/python/_epoll.pyx":83 + /* "twisted/python/_epoll.pyx":124 * * def __dealloc__(self): * if self.initialized: # <<<<<<<<<<<<<< @@ -621,7 +914,7 @@ */ if (((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->initialized) { - /* "twisted/python/_epoll.pyx":84 + /* "twisted/python/_epoll.pyx":125 * def __dealloc__(self): * if self.initialized: * close(self.fd) # <<<<<<<<<<<<<< @@ -630,7 +923,7 @@ */ close(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd); - /* "twisted/python/_epoll.pyx":85 + /* "twisted/python/_epoll.pyx":126 * if self.initialized: * close(self.fd) * self.initialized = 0 # <<<<<<<<<<<<<< @@ -645,7 +938,7 @@ __Pyx_RefNannyFinishContext(); } -/* "twisted/python/_epoll.pyx":87 +/* "twisted/python/_epoll.pyx":128 * self.initialized = 0 * * def close(self): # <<<<<<<<<<<<<< @@ -657,13 +950,17 @@ static char __pyx_doc_7twisted_6python_6_epoll_5epoll_2close[] = "\n Close the epoll file descriptor.\n "; static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_2close(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations int __pyx_t_1; PyObject *__pyx_t_2 = NULL; PyObject *__pyx_t_3 = NULL; PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; __Pyx_RefNannySetupContext("close"); - /* "twisted/python/_epoll.pyx":91 + /* "twisted/python/_epoll.pyx":132 * Close the epoll file descriptor. * """ * if self.initialized: # <<<<<<<<<<<<<< @@ -672,7 +969,7 @@ */ if (((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->initialized) { - /* "twisted/python/_epoll.pyx":92 + /* "twisted/python/_epoll.pyx":133 * """ * if self.initialized: * if close(self.fd) == -1: # <<<<<<<<<<<<<< @@ -682,18 +979,18 @@ __pyx_t_1 = (close(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd) == -1); if (__pyx_t_1) { - /* "twisted/python/_epoll.pyx":93 + /* "twisted/python/_epoll.pyx":134 * if self.initialized: * if close(self.fd) == -1: * raise IOError(errno, strerror(errno)) # <<<<<<<<<<<<<< * self.initialized = 0 * */ - __pyx_t_2 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_2 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_3)); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __Pyx_GIVEREF(__pyx_t_2); @@ -701,17 +998,17 @@ __Pyx_GIVEREF(((PyObject *)__pyx_t_3)); __pyx_t_2 = 0; __pyx_t_3 = 0; - __pyx_t_3 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_3 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_3); __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; - __Pyx_Raise(__pyx_t_3, 0, 0); + __Pyx_Raise(__pyx_t_3, 0, 0, 0); __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 93; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 134; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; - /* "twisted/python/_epoll.pyx":94 + /* "twisted/python/_epoll.pyx":135 * if close(self.fd) == -1: * raise IOError(errno, strerror(errno)) * self.initialized = 0 # <<<<<<<<<<<<<< @@ -729,7 +1026,7 @@ __Pyx_XDECREF(__pyx_t_2); __Pyx_XDECREF(__pyx_t_3); __Pyx_XDECREF(__pyx_t_4); - __Pyx_AddTraceback("twisted.python._epoll.epoll.close"); + __Pyx_AddTraceback("twisted.python._epoll.epoll.close", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); @@ -737,7 +1034,7 @@ return __pyx_r; } -/* "twisted/python/_epoll.pyx":96 +/* "twisted/python/_epoll.pyx":137 * self.initialized = 0 * * def fileno(self): # <<<<<<<<<<<<<< @@ -749,18 +1046,22 @@ static char __pyx_doc_7twisted_6python_6_epoll_5epoll_3fileno[] = "\n Return the epoll file descriptor number.\n "; static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_3fileno(PyObject *__pyx_v_self, CYTHON_UNUSED PyObject *unused) { PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; __Pyx_RefNannySetupContext("fileno"); - /* "twisted/python/_epoll.pyx":100 + /* "twisted/python/_epoll.pyx":141 * Return the epoll file descriptor number. * """ * return self.fd # <<<<<<<<<<<<<< * - * def _control(self, int op, int fd, int events): + * def register(self, int fd, int events): */ __Pyx_XDECREF(__pyx_r); - __pyx_t_1 = PyInt_FromLong(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 100; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 141; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); __pyx_r = __pyx_t_1; __pyx_t_1 = 0; @@ -770,7 +1071,7 @@ goto __pyx_L0; __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); - __Pyx_AddTraceback("twisted.python._epoll.epoll.fileno"); + __Pyx_AddTraceback("twisted.python._epoll.epoll.fileno", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); @@ -778,141 +1079,143 @@ return __pyx_r; } -/* "twisted/python/_epoll.pyx":102 +/* "twisted/python/_epoll.pyx":143 * return self.fd * - * def _control(self, int op, int fd, int events): # <<<<<<<<<<<<<< + * def register(self, int fd, int events): # <<<<<<<<<<<<<< * """ - * Modify the monitored state of a particular file descriptor. + * Add (register) a file descriptor to be monitored by self. */ -static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_4_control(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_7twisted_6python_6_epoll_5epoll_4_control[] = "\n Modify the monitored state of a particular file descriptor.\n \n Wrap epoll_ctl(2).\n\n @type op: C{int}\n @param op: One of CTL_ADD, CTL_DEL, or CTL_MOD\n\n @type fd: C{int}\n @param fd: File descriptor to modify\n\n @type events: C{int}\n @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.\n\n @raise IOError: Raised if the underlying epoll_ctl() call fails.\n "; -static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_4_control(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - int __pyx_v_op; +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_4register(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_7twisted_6python_6_epoll_5epoll_4register[] = "\n Add (register) a file descriptor to be monitored by self.\n\n This method is compatible with select.epoll.register in Python 2.6.\n\n Wrap epoll_ctl(2).\n\n @type fd: C{int}\n @param fd: File descriptor to modify\n\n @type events: C{int}\n @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.\n\n @raise IOError: Raised if the underlying epoll_ctl() call fails.\n "; +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_4register(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { int __pyx_v_fd; int __pyx_v_events; int __pyx_v_result; struct epoll_event __pyx_v_evt; PyObject *__pyx_r = NULL; - int __pyx_t_1; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; PyObject *__pyx_t_4 = NULL; - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__op,&__pyx_n_s__fd,&__pyx_n_s__events,0}; - __Pyx_RefNannySetupContext("_control"); - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); - PyObject* values[3] = {0,0,0}; - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); - case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 0: - values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__op); - if (likely(values[0])) kw_args--; - else goto __pyx_L5_argtuple_error; - case 1: - values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__fd); - if (likely(values[1])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("_control", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - case 2: - values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__events); - if (likely(values[2])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("_control", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "_control") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - __pyx_v_op = __Pyx_PyInt_AsInt(values[0]); if (unlikely((__pyx_v_op == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_fd = __Pyx_PyInt_AsInt(values[1]); if (unlikely((__pyx_v_fd == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_events = __Pyx_PyInt_AsInt(values[2]); if (unlikely((__pyx_v_events == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { - goto __pyx_L5_argtuple_error; - } else { - __pyx_v_op = __Pyx_PyInt_AsInt(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_op == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_fd = __Pyx_PyInt_AsInt(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_fd == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_events = __Pyx_PyInt_AsInt(PyTuple_GET_ITEM(__pyx_args, 2)); if (unlikely((__pyx_v_events == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__fd,&__pyx_n_s__events,0}; + __Pyx_RefNannySetupContext("register"); + { + PyObject* values[2] = {0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 0: + values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__fd); + if (likely(values[0])) kw_args--; + else goto __pyx_L5_argtuple_error; + case 1: + values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__events); + if (likely(values[1])) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("register", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "register") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + } + __pyx_v_fd = __Pyx_PyInt_AsInt(values[0]); if (unlikely((__pyx_v_fd == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_events = __Pyx_PyInt_AsInt(values[1]); if (unlikely((__pyx_v_events == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("_control", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 102; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __Pyx_RaiseArgtupleInvalid("register", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 143; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; - __Pyx_AddTraceback("twisted.python._epoll.epoll._control"); + __Pyx_AddTraceback("twisted.python._epoll.epoll.register", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - /* "twisted/python/_epoll.pyx":121 + /* "twisted/python/_epoll.pyx":161 * cdef int result * cdef epoll_event evt * evt.events = events # <<<<<<<<<<<<<< * evt.data.fd = fd - * result = epoll_ctl(self.fd, op, fd, &evt) + * result = epoll_ctl(self.fd, CTL_ADD, fd, &evt) */ __pyx_v_evt.events = __pyx_v_events; - /* "twisted/python/_epoll.pyx":122 + /* "twisted/python/_epoll.pyx":162 * cdef epoll_event evt * evt.events = events * evt.data.fd = fd # <<<<<<<<<<<<<< - * result = epoll_ctl(self.fd, op, fd, &evt) + * result = epoll_ctl(self.fd, CTL_ADD, fd, &evt) * if result == -1: */ __pyx_v_evt.data.fd = __pyx_v_fd; - /* "twisted/python/_epoll.pyx":123 + /* "twisted/python/_epoll.pyx":163 * evt.events = events * evt.data.fd = fd - * result = epoll_ctl(self.fd, op, fd, &evt) # <<<<<<<<<<<<<< + * result = epoll_ctl(self.fd, CTL_ADD, fd, &evt) # <<<<<<<<<<<<<< * if result == -1: * raise IOError(errno, strerror(errno)) */ - __pyx_v_result = epoll_ctl(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd, __pyx_v_op, __pyx_v_fd, (&__pyx_v_evt)); + __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__CTL_ADD); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyInt_AsInt(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 163; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_result = epoll_ctl(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd, __pyx_t_2, __pyx_v_fd, (&__pyx_v_evt)); - /* "twisted/python/_epoll.pyx":124 + /* "twisted/python/_epoll.pyx":164 * evt.data.fd = fd - * result = epoll_ctl(self.fd, op, fd, &evt) + * result = epoll_ctl(self.fd, CTL_ADD, fd, &evt) * if result == -1: # <<<<<<<<<<<<<< * raise IOError(errno, strerror(errno)) * */ - __pyx_t_1 = (__pyx_v_result == -1); - if (__pyx_t_1) { + __pyx_t_3 = (__pyx_v_result == -1); + if (__pyx_t_3) { - /* "twisted/python/_epoll.pyx":125 - * result = epoll_ctl(self.fd, op, fd, &evt) + /* "twisted/python/_epoll.pyx":165 + * result = epoll_ctl(self.fd, CTL_ADD, fd, &evt) * if result == -1: * raise IOError(errno, strerror(errno)) # <<<<<<<<<<<<<< * - * def wait(self, unsigned int maxevents, int timeout): + * def unregister(self, int fd): */ - __pyx_t_2 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(((PyObject *)__pyx_t_3)); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_4)); - PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); - __Pyx_GIVEREF(__pyx_t_2); - PyTuple_SET_ITEM(__pyx_t_4, 1, ((PyObject *)__pyx_t_3)); - __Pyx_GIVEREF(((PyObject *)__pyx_t_3)); - __pyx_t_2 = 0; - __pyx_t_3 = 0; - __pyx_t_3 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; - __Pyx_Raise(__pyx_t_3, 0, 0); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 125; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_5)); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 1, ((PyObject *)__pyx_t_4)); + __Pyx_GIVEREF(((PyObject *)__pyx_t_4)); + __pyx_t_1 = 0; + __pyx_t_4 = 0; + __pyx_t_4 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} goto __pyx_L6; } __pyx_L6:; @@ -920,10 +1223,10 @@ __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_1); __Pyx_XDECREF(__pyx_t_4); - __Pyx_AddTraceback("twisted.python._epoll.epoll._control"); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("twisted.python._epoll.epoll.register", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; __Pyx_XGIVEREF(__pyx_r); @@ -931,299 +1234,618 @@ return __pyx_r; } -/* "twisted/python/_epoll.pyx":127 +/* "twisted/python/_epoll.pyx":167 * raise IOError(errno, strerror(errno)) * - * def wait(self, unsigned int maxevents, int timeout): # <<<<<<<<<<<<<< + * def unregister(self, int fd): # <<<<<<<<<<<<<< * """ - * Wait for an I/O event, wrap epoll_wait(2). + * Remove (unregister) a file descriptor monitored by self. */ -static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_5wait(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ -static char __pyx_doc_7twisted_6python_6_epoll_5epoll_5wait[] = "\n Wait for an I/O event, wrap epoll_wait(2).\n\n @type maxevents: C{int}\n @param maxevents: Maximum number of events returned.\n\n @type timeout: C{int}\n @param timeout: Maximum time waiting for events. 0 makes it return\n immediately whereas -1 makes it wait indefinitely.\n \n @raise IOError: Raised if the underlying epoll_wait() call fails.\n "; -static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_5wait(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { - unsigned int __pyx_v_maxevents; - int __pyx_v_timeout; - struct epoll_event *__pyx_v_events; - int __pyx_v_result; - int __pyx_v_nbytes; +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_5unregister(PyObject *__pyx_v_self, PyObject *__pyx_arg_fd); /*proto*/ +static char __pyx_doc_7twisted_6python_6_epoll_5epoll_5unregister[] = "\n Remove (unregister) a file descriptor monitored by self.\n\n This method is compatible with select.epoll.unregister in Python 2.6.\n\n Wrap epoll_ctl(2).\n\n @type fd: C{int}\n @param fd: File descriptor to modify\n\n @raise IOError: Raised if the underlying epoll_ctl() call fails.\n "; +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_5unregister(PyObject *__pyx_v_self, PyObject *__pyx_arg_fd) { int __pyx_v_fd; - PyThreadState *__pyx_v__save; - PyObject *__pyx_v_results; - long __pyx_v_i; + int __pyx_v_result; + struct epoll_event __pyx_v_evt; PyObject *__pyx_r = NULL; - int __pyx_t_1; - PyObject *__pyx_t_2 = NULL; - PyObject *__pyx_t_3 = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; PyObject *__pyx_t_4 = NULL; - int __pyx_t_5; - int __pyx_t_6; - static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__maxevents,&__pyx_n_s__timeout,0}; - __Pyx_RefNannySetupContext("wait"); - if (unlikely(__pyx_kwds)) { - Py_ssize_t kw_args = PyDict_Size(__pyx_kwds); - PyObject* values[2] = {0,0}; - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); - case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); - case 0: break; - default: goto __pyx_L5_argtuple_error; - } - switch (PyTuple_GET_SIZE(__pyx_args)) { - case 0: - values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__maxevents); - if (likely(values[0])) kw_args--; - else goto __pyx_L5_argtuple_error; - case 1: - values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__timeout); - if (likely(values[1])) kw_args--; - else { - __Pyx_RaiseArgtupleInvalid("wait", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - } - if (unlikely(kw_args > 0)) { - if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "wait") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } - __pyx_v_maxevents = __Pyx_PyInt_AsUnsignedInt(values[0]); if (unlikely((__pyx_v_maxevents == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_timeout = __Pyx_PyInt_AsInt(values[1]); if (unlikely((__pyx_v_timeout == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { - goto __pyx_L5_argtuple_error; - } else { - __pyx_v_maxevents = __Pyx_PyInt_AsUnsignedInt(PyTuple_GET_ITEM(__pyx_args, 0)); if (unlikely((__pyx_v_maxevents == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L3_error;} - __pyx_v_timeout = __Pyx_PyInt_AsInt(PyTuple_GET_ITEM(__pyx_args, 1)); if (unlikely((__pyx_v_timeout == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + __Pyx_RefNannySetupContext("unregister"); + assert(__pyx_arg_fd); { + __pyx_v_fd = __Pyx_PyInt_AsInt(__pyx_arg_fd); if (unlikely((__pyx_v_fd == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L3_error;} } goto __pyx_L4_argument_unpacking_done; - __pyx_L5_argtuple_error:; - __Pyx_RaiseArgtupleInvalid("wait", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 127; __pyx_clineno = __LINE__; goto __pyx_L3_error;} __pyx_L3_error:; - __Pyx_AddTraceback("twisted.python._epoll.epoll.wait"); + __Pyx_AddTraceback("twisted.python._epoll.epoll.unregister", __pyx_clineno, __pyx_lineno, __pyx_filename); __Pyx_RefNannyFinishContext(); return NULL; __pyx_L4_argument_unpacking_done:; - __pyx_v_results = ((PyObject*)Py_None); __Pyx_INCREF(Py_None); - /* "twisted/python/_epoll.pyx":146 - * cdef PyThreadState *_save - * - * nbytes = sizeof(epoll_event) * maxevents # <<<<<<<<<<<<<< - * events = malloc(nbytes) - * memset(events, 0, nbytes) + /* "twisted/python/_epoll.pyx":183 + * cdef epoll_event evt + * # We don't have to fill evt.events for CTL_DEL. + * evt.data.fd = fd # <<<<<<<<<<<<<< + * result = epoll_ctl(self.fd, CTL_DEL, fd, &evt) + * if result == -1: */ - __pyx_v_nbytes = ((sizeof(struct epoll_event)) * __pyx_v_maxevents); + __pyx_v_evt.data.fd = __pyx_v_fd; - /* "twisted/python/_epoll.pyx":147 - * - * nbytes = sizeof(epoll_event) * maxevents - * events = malloc(nbytes) # <<<<<<<<<<<<<< - * memset(events, 0, nbytes) - * try: + /* "twisted/python/_epoll.pyx":184 + * # We don't have to fill evt.events for CTL_DEL. + * evt.data.fd = fd + * result = epoll_ctl(self.fd, CTL_DEL, fd, &evt) # <<<<<<<<<<<<<< + * if result == -1: + * raise IOError(errno, strerror(errno)) */ - __pyx_v_events = ((struct epoll_event *)malloc(__pyx_v_nbytes)); + __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__CTL_DEL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 184; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyInt_AsInt(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 184; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_result = epoll_ctl(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd, __pyx_t_2, __pyx_v_fd, (&__pyx_v_evt)); - /* "twisted/python/_epoll.pyx":148 - * nbytes = sizeof(epoll_event) * maxevents - * events = malloc(nbytes) - * memset(events, 0, nbytes) # <<<<<<<<<<<<<< - * try: - * fd = self.fd + /* "twisted/python/_epoll.pyx":185 + * evt.data.fd = fd + * result = epoll_ctl(self.fd, CTL_DEL, fd, &evt) + * if result == -1: # <<<<<<<<<<<<<< + * raise IOError(errno, strerror(errno)) + * */ - memset(__pyx_v_events, 0, __pyx_v_nbytes); + __pyx_t_3 = (__pyx_v_result == -1); + if (__pyx_t_3) { - /* "twisted/python/_epoll.pyx":149 - * events = malloc(nbytes) - * memset(events, 0, nbytes) - * try: # <<<<<<<<<<<<<< - * fd = self.fd + /* "twisted/python/_epoll.pyx":186 + * result = epoll_ctl(self.fd, CTL_DEL, fd, &evt) + * if result == -1: + * raise IOError(errno, strerror(errno)) # <<<<<<<<<<<<<< * + * def modify(self, int fd, int events): */ - /*try:*/ { + __pyx_t_1 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 186; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 186; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_4)); + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 186; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_5)); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 1, ((PyObject *)__pyx_t_4)); + __Pyx_GIVEREF(((PyObject *)__pyx_t_4)); + __pyx_t_1 = 0; + __pyx_t_4 = 0; + __pyx_t_4 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 186; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 186; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + goto __pyx_L5; + } + __pyx_L5:; + + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("twisted.python._epoll.epoll.unregister", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} - /* "twisted/python/_epoll.pyx":150 - * memset(events, 0, nbytes) - * try: - * fd = self.fd # <<<<<<<<<<<<<< +/* "twisted/python/_epoll.pyx":188 + * raise IOError(errno, strerror(errno)) * - * _save = PyEval_SaveThread() + * def modify(self, int fd, int events): # <<<<<<<<<<<<<< + * """ + * Modify the modified state of a file descriptor monitored by self. */ - __pyx_v_fd = ((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd; - /* "twisted/python/_epoll.pyx":152 - * fd = self.fd - * - * _save = PyEval_SaveThread() # <<<<<<<<<<<<<< - * result = epoll_wait(fd, events, maxevents, timeout) - * PyEval_RestoreThread(_save) +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_6modify(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_7twisted_6python_6_epoll_5epoll_6modify[] = "\n Modify the modified state of a file descriptor monitored by self.\n\n This method is compatible with select.epoll.modify in Python 2.6.\n\n Wrap epoll_ctl(2).\n\n @type fd: C{int}\n @param fd: File descriptor to modify\n\n @type events: C{int}\n @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.\n\n @raise IOError: Raised if the underlying epoll_ctl() call fails.\n "; +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_6modify(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + int __pyx_v_fd; + int __pyx_v_events; + int __pyx_v_result; + struct epoll_event __pyx_v_evt; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_t_2; + int __pyx_t_3; + PyObject *__pyx_t_4 = NULL; + PyObject *__pyx_t_5 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__fd,&__pyx_n_s__events,0}; + __Pyx_RefNannySetupContext("modify"); + { + PyObject* values[2] = {0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 0: + values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__fd); + if (likely(values[0])) kw_args--; + else goto __pyx_L5_argtuple_error; + case 1: + values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__events); + if (likely(values[1])) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("modify", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "modify") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + } + __pyx_v_fd = __Pyx_PyInt_AsInt(values[0]); if (unlikely((__pyx_v_fd == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_events = __Pyx_PyInt_AsInt(values[1]); if (unlikely((__pyx_v_events == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("modify", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 188; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_L3_error:; + __Pyx_AddTraceback("twisted.python._epoll.epoll.modify", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + + /* "twisted/python/_epoll.pyx":206 + * cdef int result + * cdef epoll_event evt + * evt.events = events # <<<<<<<<<<<<<< + * evt.data.fd = fd + * result = epoll_ctl(self.fd, CTL_MOD, fd, &evt) */ - __pyx_v__save = PyEval_SaveThread(); + __pyx_v_evt.events = __pyx_v_events; - /* "twisted/python/_epoll.pyx":153 - * - * _save = PyEval_SaveThread() - * result = epoll_wait(fd, events, maxevents, timeout) # <<<<<<<<<<<<<< - * PyEval_RestoreThread(_save) + /* "twisted/python/_epoll.pyx":207 + * cdef epoll_event evt + * evt.events = events + * evt.data.fd = fd # <<<<<<<<<<<<<< + * result = epoll_ctl(self.fd, CTL_MOD, fd, &evt) + * if result == -1: + */ + __pyx_v_evt.data.fd = __pyx_v_fd; + + /* "twisted/python/_epoll.pyx":208 + * evt.events = events + * evt.data.fd = fd + * result = epoll_ctl(self.fd, CTL_MOD, fd, &evt) # <<<<<<<<<<<<<< + * if result == -1: + * raise IOError(errno, strerror(errno)) + */ + __pyx_t_1 = __Pyx_GetName(__pyx_m, __pyx_n_s__CTL_MOD); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 208; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_2 = __Pyx_PyInt_AsInt(__pyx_t_1); if (unlikely((__pyx_t_2 == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 208; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_v_result = epoll_ctl(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd, __pyx_t_2, __pyx_v_fd, (&__pyx_v_evt)); + + /* "twisted/python/_epoll.pyx":209 + * evt.data.fd = fd + * result = epoll_ctl(self.fd, CTL_MOD, fd, &evt) + * if result == -1: # <<<<<<<<<<<<<< + * raise IOError(errno, strerror(errno)) * */ - __pyx_v_result = epoll_wait(__pyx_v_fd, __pyx_v_events, __pyx_v_maxevents, __pyx_v_timeout); + __pyx_t_3 = (__pyx_v_result == -1); + if (__pyx_t_3) { - /* "twisted/python/_epoll.pyx":154 - * _save = PyEval_SaveThread() - * result = epoll_wait(fd, events, maxevents, timeout) - * PyEval_RestoreThread(_save) # <<<<<<<<<<<<<< + /* "twisted/python/_epoll.pyx":210 + * result = epoll_ctl(self.fd, CTL_MOD, fd, &evt) + * if result == -1: + * raise IOError(errno, strerror(errno)) # <<<<<<<<<<<<<< * - * if result == -1: + * def _control(self, int op, int fd, int events): */ - PyEval_RestoreThread(__pyx_v__save); + __pyx_t_1 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 210; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __pyx_t_4 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 210; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_4)); + __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 210; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_5)); + PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_1); + __Pyx_GIVEREF(__pyx_t_1); + PyTuple_SET_ITEM(__pyx_t_5, 1, ((PyObject *)__pyx_t_4)); + __Pyx_GIVEREF(((PyObject *)__pyx_t_4)); + __pyx_t_1 = 0; + __pyx_t_4 = 0; + __pyx_t_4 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_5), NULL); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 210; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_4); + __Pyx_DECREF(((PyObject *)__pyx_t_5)); __pyx_t_5 = 0; + __Pyx_Raise(__pyx_t_4, 0, 0, 0); + __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0; + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 210; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + goto __pyx_L6; + } + __pyx_L6:; + + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_XDECREF(__pyx_t_5); + __Pyx_AddTraceback("twisted.python._epoll.epoll.modify", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} - /* "twisted/python/_epoll.pyx":156 - * PyEval_RestoreThread(_save) +/* "twisted/python/_epoll.pyx":212 + * raise IOError(errno, strerror(errno)) * - * if result == -1: # <<<<<<<<<<<<<< - * raise IOError(errno, strerror(errno)) - * results = [] + * def _control(self, int op, int fd, int events): # <<<<<<<<<<<<<< + * """ + * Modify the monitored state of a particular file descriptor. */ - __pyx_t_1 = (__pyx_v_result == -1); - if (__pyx_t_1) { - /* "twisted/python/_epoll.pyx":157 +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_7_control(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_7twisted_6python_6_epoll_5epoll_7_control[] = "\n Modify the monitored state of a particular file descriptor.\n \n Wrap epoll_ctl(2).\n\n @type op: C{int}\n @param op: One of CTL_ADD, CTL_DEL, or CTL_MOD\n\n @type fd: C{int}\n @param fd: File descriptor to modify\n\n @type events: C{int}\n @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET.\n\n @raise IOError: Raised if the underlying epoll_ctl() call fails.\n "; +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_7_control(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + int __pyx_v_op; + int __pyx_v_fd; + int __pyx_v_events; + int __pyx_v_result; + struct epoll_event __pyx_v_evt; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + int __pyx_t_1; + PyObject *__pyx_t_2 = NULL; + PyObject *__pyx_t_3 = NULL; + PyObject *__pyx_t_4 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__op,&__pyx_n_s__fd,&__pyx_n_s__events,0}; + __Pyx_RefNannySetupContext("_control"); + { + PyObject* values[3] = {0,0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 0: + values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__op); + if (likely(values[0])) kw_args--; + else goto __pyx_L5_argtuple_error; + case 1: + values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__fd); + if (likely(values[1])) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_control", 1, 3, 3, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + case 2: + values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__events); + if (likely(values[2])) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("_control", 1, 3, 3, 2); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "_control") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 3) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + values[2] = PyTuple_GET_ITEM(__pyx_args, 2); + } + __pyx_v_op = __Pyx_PyInt_AsInt(values[0]); if (unlikely((__pyx_v_op == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_fd = __Pyx_PyInt_AsInt(values[1]); if (unlikely((__pyx_v_fd == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_events = __Pyx_PyInt_AsInt(values[2]); if (unlikely((__pyx_v_events == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("_control", 1, 3, 3, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 212; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_L3_error:; + __Pyx_AddTraceback("twisted.python._epoll.epoll._control", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + + /* "twisted/python/_epoll.pyx":231 + * cdef int result + * cdef epoll_event evt + * evt.events = events # <<<<<<<<<<<<<< + * evt.data.fd = fd + * result = epoll_ctl(self.fd, op, fd, &evt) + */ + __pyx_v_evt.events = __pyx_v_events; + + /* "twisted/python/_epoll.pyx":232 + * cdef epoll_event evt + * evt.events = events + * evt.data.fd = fd # <<<<<<<<<<<<<< + * result = epoll_ctl(self.fd, op, fd, &evt) + * if result == -1: + */ + __pyx_v_evt.data.fd = __pyx_v_fd; + + /* "twisted/python/_epoll.pyx":233 + * evt.events = events + * evt.data.fd = fd + * result = epoll_ctl(self.fd, op, fd, &evt) # <<<<<<<<<<<<<< + * if result == -1: + * raise IOError(errno, strerror(errno)) + */ + __pyx_v_result = epoll_ctl(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd, __pyx_v_op, __pyx_v_fd, (&__pyx_v_evt)); + + /* "twisted/python/_epoll.pyx":234 + * evt.data.fd = fd + * result = epoll_ctl(self.fd, op, fd, &evt) + * if result == -1: # <<<<<<<<<<<<<< + * raise IOError(errno, strerror(errno)) * - * if result == -1: - * raise IOError(errno, strerror(errno)) # <<<<<<<<<<<<<< - * results = [] - * for i from 0 <= i < result: */ - __pyx_t_2 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L7;} - __Pyx_GOTREF(__pyx_t_2); - __pyx_t_3 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L7;} - __Pyx_GOTREF(((PyObject *)__pyx_t_3)); - __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L7;} - __Pyx_GOTREF(((PyObject *)__pyx_t_4)); - PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); - __Pyx_GIVEREF(__pyx_t_2); - PyTuple_SET_ITEM(__pyx_t_4, 1, ((PyObject *)__pyx_t_3)); - __Pyx_GIVEREF(((PyObject *)__pyx_t_3)); - __pyx_t_2 = 0; - __pyx_t_3 = 0; - __pyx_t_3 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L7;} - __Pyx_GOTREF(__pyx_t_3); - __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; - __Pyx_Raise(__pyx_t_3, 0, 0); - __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; - {__pyx_filename = __pyx_f[0]; __pyx_lineno = 157; __pyx_clineno = __LINE__; goto __pyx_L7;} - goto __pyx_L9; - } - __pyx_L9:; + __pyx_t_1 = (__pyx_v_result == -1); + if (__pyx_t_1) { - /* "twisted/python/_epoll.pyx":158 - * if result == -1: - * raise IOError(errno, strerror(errno)) - * results = [] # <<<<<<<<<<<<<< - * for i from 0 <= i < result: - * results.append((events[i].data.fd, events[i].events)) + /* "twisted/python/_epoll.pyx":235 + * result = epoll_ctl(self.fd, op, fd, &evt) + * if result == -1: + * raise IOError(errno, strerror(errno)) # <<<<<<<<<<<<<< + * + * def wait(self, unsigned int maxevents, int timeout): */ - __pyx_t_3 = PyList_New(0); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 158; __pyx_clineno = __LINE__; goto __pyx_L7;} + __pyx_t_2 = PyInt_FromLong(errno); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 235; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_2); + __pyx_t_3 = PyBytes_FromString(strerror(errno)); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 235; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(((PyObject *)__pyx_t_3)); - __Pyx_DECREF(((PyObject *)__pyx_v_results)); - __pyx_v_results = __pyx_t_3; + __pyx_t_4 = PyTuple_New(2); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 235; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(((PyObject *)__pyx_t_4)); + PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); + __Pyx_GIVEREF(__pyx_t_2); + PyTuple_SET_ITEM(__pyx_t_4, 1, ((PyObject *)__pyx_t_3)); + __Pyx_GIVEREF(((PyObject *)__pyx_t_3)); + __pyx_t_2 = 0; __pyx_t_3 = 0; + __pyx_t_3 = PyObject_Call(__pyx_builtin_IOError, ((PyObject *)__pyx_t_4), NULL); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 235; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_3); + __Pyx_DECREF(((PyObject *)__pyx_t_4)); __pyx_t_4 = 0; + __Pyx_Raise(__pyx_t_3, 0, 0, 0); + __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0; + {__pyx_filename = __pyx_f[0]; __pyx_lineno = 235; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + goto __pyx_L6; + } + __pyx_L6:; - /* "twisted/python/_epoll.pyx":159 - * raise IOError(errno, strerror(errno)) - * results = [] - * for i from 0 <= i < result: # <<<<<<<<<<<<<< - * results.append((events[i].data.fd, events[i].events)) - * return results - */ - __pyx_t_5 = __pyx_v_result; - for (__pyx_v_i = 0; __pyx_v_i < __pyx_t_5; __pyx_v_i++) { + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_2); + __Pyx_XDECREF(__pyx_t_3); + __Pyx_XDECREF(__pyx_t_4); + __Pyx_AddTraceback("twisted.python._epoll.epoll._control", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} - /* "twisted/python/_epoll.pyx":160 - * results = [] - * for i from 0 <= i < result: - * results.append((events[i].data.fd, events[i].events)) # <<<<<<<<<<<<<< - * return results - * finally: +/* "twisted/python/_epoll.pyx":237 + * raise IOError(errno, strerror(errno)) + * + * def wait(self, unsigned int maxevents, int timeout): # <<<<<<<<<<<<<< + * """ + * Wait for an I/O event, wrap epoll_wait(2). */ - if (unlikely(__pyx_v_results == Py_None)) { - PyErr_SetString(PyExc_AttributeError, "'NoneType' object has no attribute 'append'"); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L7;} + +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_8wait(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_7twisted_6python_6_epoll_5epoll_8wait[] = "\n Wait for an I/O event, wrap epoll_wait(2).\n\n @type maxevents: C{int}\n @param maxevents: Maximum number of events returned.\n\n @type timeout: C{int}\n @param timeout: Maximum time in milliseconds waiting for events. 0\n makes it return immediately whereas -1 makes it wait indefinitely.\n \n @raise IOError: Raised if the underlying epoll_wait() call fails.\n "; +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_8wait(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + unsigned int __pyx_v_maxevents; + int __pyx_v_timeout; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__maxevents,&__pyx_n_s__timeout,0}; + __Pyx_RefNannySetupContext("wait"); + { + PyObject* values[2] = {0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; } - __pyx_t_3 = PyInt_FromLong((__pyx_v_events[__pyx_v_i]).data.fd); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L7;} - __Pyx_GOTREF(__pyx_t_3); - __pyx_t_4 = PyInt_FromLong(((int)(__pyx_v_events[__pyx_v_i]).events)); if (unlikely(!__pyx_t_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L7;} - __Pyx_GOTREF(__pyx_t_4); - __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L7;} - __Pyx_GOTREF(((PyObject *)__pyx_t_2)); - PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_3); - __Pyx_GIVEREF(__pyx_t_3); - PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_4); - __Pyx_GIVEREF(__pyx_t_4); - __pyx_t_3 = 0; - __pyx_t_4 = 0; - __pyx_t_6 = PyList_Append(__pyx_v_results, ((PyObject *)__pyx_t_2)); if (unlikely(__pyx_t_6 == -1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 160; __pyx_clineno = __LINE__; goto __pyx_L7;} - __Pyx_DECREF(((PyObject *)__pyx_t_2)); __pyx_t_2 = 0; + kw_args = PyDict_Size(__pyx_kwds); + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 0: + values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__maxevents); + if (likely(values[0])) kw_args--; + else goto __pyx_L5_argtuple_error; + case 1: + values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s__timeout); + if (likely(values[1])) kw_args--; + else { + __Pyx_RaiseArgtupleInvalid("wait", 1, 2, 2, 1); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "wait") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } else if (PyTuple_GET_SIZE(__pyx_args) != 2) { + goto __pyx_L5_argtuple_error; + } else { + values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + values[1] = PyTuple_GET_ITEM(__pyx_args, 1); } + __pyx_v_maxevents = __Pyx_PyInt_AsUnsignedInt(values[0]); if (unlikely((__pyx_v_maxevents == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_v_timeout = __Pyx_PyInt_AsInt(values[1]); if (unlikely((__pyx_v_timeout == (int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("wait", 1, 2, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 237; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_L3_error:; + __Pyx_AddTraceback("twisted.python._epoll.epoll.wait", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; - /* "twisted/python/_epoll.pyx":161 - * for i from 0 <= i < result: - * results.append((events[i].data.fd, events[i].events)) - * return results # <<<<<<<<<<<<<< - * finally: - * free(events) + /* "twisted/python/_epoll.pyx":250 + * @raise IOError: Raised if the underlying epoll_wait() call fails. + * """ + * return call_epoll_wait(self.fd, maxevents, timeout) # <<<<<<<<<<<<<< + * + * def poll(self, float timeout=-1, unsigned int maxevents=1024): */ - __Pyx_XDECREF(__pyx_r); - __Pyx_INCREF(((PyObject *)__pyx_v_results)); - __pyx_r = ((PyObject *)__pyx_v_results); - goto __pyx_L6; - } + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_7twisted_6python_6_epoll_call_epoll_wait(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd, __pyx_v_maxevents, __pyx_v_timeout); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 250; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; - /* "twisted/python/_epoll.pyx":163 - * return results - * finally: - * free(events) # <<<<<<<<<<<<<< + __pyx_r = Py_None; __Pyx_INCREF(Py_None); + goto __pyx_L0; + __pyx_L1_error:; + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("twisted.python._epoll.epoll.wait", __pyx_clineno, __pyx_lineno, __pyx_filename); + __pyx_r = NULL; + __pyx_L0:; + __Pyx_XGIVEREF(__pyx_r); + __Pyx_RefNannyFinishContext(); + return __pyx_r; +} + +/* "twisted/python/_epoll.pyx":252 + * return call_epoll_wait(self.fd, maxevents, timeout) * - * CTL_ADD = EPOLL_CTL_ADD + * def poll(self, float timeout=-1, unsigned int maxevents=1024): # <<<<<<<<<<<<<< + * """ + * Wait for an I/O event, wrap epoll_wait(2). */ - /*finally:*/ { - int __pyx_why; - PyObject *__pyx_exc_type, *__pyx_exc_value, *__pyx_exc_tb; - int __pyx_exc_lineno; - __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0; - __pyx_why = 0; goto __pyx_L8; - __pyx_L6: __pyx_exc_type = 0; __pyx_exc_value = 0; __pyx_exc_tb = 0; __pyx_exc_lineno = 0; - __pyx_why = 3; goto __pyx_L8; - __pyx_L7: { - __pyx_why = 4; - __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0; - __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0; - __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0; - __Pyx_ErrFetch(&__pyx_exc_type, &__pyx_exc_value, &__pyx_exc_tb); - __pyx_exc_lineno = __pyx_lineno; - goto __pyx_L8; - } - __pyx_L8:; - free(__pyx_v_events); - switch (__pyx_why) { - case 3: goto __pyx_L0; - case 4: { - __Pyx_ErrRestore(__pyx_exc_type, __pyx_exc_value, __pyx_exc_tb); - __pyx_lineno = __pyx_exc_lineno; - __pyx_exc_type = 0; - __pyx_exc_value = 0; - __pyx_exc_tb = 0; - goto __pyx_L1_error; + +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_9poll(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/ +static char __pyx_doc_7twisted_6python_6_epoll_5epoll_9poll[] = "\n Wait for an I/O event, wrap epoll_wait(2).\n\n This method is compatible with select.epoll.poll in Python 2.6.\n\n @type maxevents: C{int}\n @param maxevents: Maximum number of events returned.\n\n @type timeout: C{int}\n @param timeout: Maximum time waiting for events. 0 makes it return\n immediately whereas -1 makes it wait indefinitely.\n \n @raise IOError: Raised if the underlying epoll_wait() call fails.\n "; +static PyObject *__pyx_pf_7twisted_6python_6_epoll_5epoll_9poll(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) { + float __pyx_v_timeout; + unsigned int __pyx_v_maxevents; + PyObject *__pyx_r = NULL; + __Pyx_RefNannyDeclarations + PyObject *__pyx_t_1 = NULL; + int __pyx_lineno = 0; + const char *__pyx_filename = NULL; + int __pyx_clineno = 0; + static PyObject **__pyx_pyargnames[] = {&__pyx_n_s__timeout,&__pyx_n_s__maxevents,0}; + __Pyx_RefNannySetupContext("poll"); + { + PyObject* values[2] = {0,0}; + if (unlikely(__pyx_kwds)) { + Py_ssize_t kw_args; + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; + } + kw_args = PyDict_Size(__pyx_kwds); + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 0: + if (kw_args > 0) { + PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__timeout); + if (value) { values[0] = value; kw_args--; } + } + case 1: + if (kw_args > 0) { + PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s__maxevents); + if (value) { values[1] = value; kw_args--; } + } + } + if (unlikely(kw_args > 0)) { + if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, PyTuple_GET_SIZE(__pyx_args), "poll") < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 252; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } + } else { + switch (PyTuple_GET_SIZE(__pyx_args)) { + case 2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1); + case 1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0); + case 0: break; + default: goto __pyx_L5_argtuple_error; } } + if (values[0]) { + __pyx_v_timeout = __pyx_PyFloat_AsDouble(values[0]); if (unlikely((__pyx_v_timeout == (float)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 252; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } else { + __pyx_v_timeout = ((float)-1.0); + } + if (values[1]) { + __pyx_v_maxevents = __Pyx_PyInt_AsUnsignedInt(values[1]); if (unlikely((__pyx_v_maxevents == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 252; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + } else { + __pyx_v_maxevents = ((unsigned int)1024); + } } + goto __pyx_L4_argument_unpacking_done; + __pyx_L5_argtuple_error:; + __Pyx_RaiseArgtupleInvalid("poll", 0, 0, 2, PyTuple_GET_SIZE(__pyx_args)); {__pyx_filename = __pyx_f[0]; __pyx_lineno = 252; __pyx_clineno = __LINE__; goto __pyx_L3_error;} + __pyx_L3_error:; + __Pyx_AddTraceback("twisted.python._epoll.epoll.poll", __pyx_clineno, __pyx_lineno, __pyx_filename); + __Pyx_RefNannyFinishContext(); + return NULL; + __pyx_L4_argument_unpacking_done:; + + /* "twisted/python/_epoll.pyx":267 + * @raise IOError: Raised if the underlying epoll_wait() call fails. + * """ + * return call_epoll_wait(self.fd, maxevents, (timeout * 1000.0)) # <<<<<<<<<<<<<< + * + * + */ + __Pyx_XDECREF(__pyx_r); + __pyx_t_1 = __pyx_f_7twisted_6python_6_epoll_call_epoll_wait(((struct __pyx_obj_7twisted_6python_6_epoll_epoll *)__pyx_v_self)->fd, __pyx_v_maxevents, ((int)(__pyx_v_timeout * 1000.0))); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 267; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + __pyx_r = __pyx_t_1; + __pyx_t_1 = 0; + goto __pyx_L0; __pyx_r = Py_None; __Pyx_INCREF(Py_None); goto __pyx_L0; __pyx_L1_error:; - __Pyx_XDECREF(__pyx_t_2); - __Pyx_XDECREF(__pyx_t_3); - __Pyx_XDECREF(__pyx_t_4); - __Pyx_AddTraceback("twisted.python._epoll.epoll.wait"); + __Pyx_XDECREF(__pyx_t_1); + __Pyx_AddTraceback("twisted.python._epoll.epoll.poll", __pyx_clineno, __pyx_lineno, __pyx_filename); __pyx_r = NULL; __pyx_L0:; - __Pyx_DECREF(__pyx_v_results); __Pyx_XGIVEREF(__pyx_r); __Pyx_RefNannyFinishContext(); return __pyx_r; @@ -1251,8 +1873,12 @@ static PyMethodDef __pyx_methods_7twisted_6python_6_epoll_epoll[] = { {__Pyx_NAMESTR("close"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_2close, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_2close)}, {__Pyx_NAMESTR("fileno"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_3fileno, METH_NOARGS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_3fileno)}, - {__Pyx_NAMESTR("_control"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_4_control, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_4_control)}, - {__Pyx_NAMESTR("wait"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_5wait, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_5wait)}, + {__Pyx_NAMESTR("register"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_4register, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_4register)}, + {__Pyx_NAMESTR("unregister"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_5unregister, METH_O, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_5unregister)}, + {__Pyx_NAMESTR("modify"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_6modify, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_6modify)}, + {__Pyx_NAMESTR("_control"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_7_control, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_7_control)}, + {__Pyx_NAMESTR("wait"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_8wait, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_8wait)}, + {__Pyx_NAMESTR("poll"), (PyCFunction)__pyx_pf_7twisted_6python_6_epoll_5epoll_9poll, METH_VARARGS|METH_KEYWORDS, __Pyx_DOCSTR(__pyx_doc_7twisted_6python_6_epoll_5epoll_9poll)}, {0, 0, 0, 0} }; @@ -1432,6 +2058,17 @@ {&__pyx_n_s__CTL_ADD, __pyx_k__CTL_ADD, sizeof(__pyx_k__CTL_ADD), 0, 0, 1, 1}, {&__pyx_n_s__CTL_DEL, __pyx_k__CTL_DEL, sizeof(__pyx_k__CTL_DEL), 0, 0, 1, 1}, {&__pyx_n_s__CTL_MOD, __pyx_k__CTL_MOD, sizeof(__pyx_k__CTL_MOD), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLERR, __pyx_k__EPOLLERR, sizeof(__pyx_k__EPOLLERR), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLET, __pyx_k__EPOLLET, sizeof(__pyx_k__EPOLLET), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLHUP, __pyx_k__EPOLLHUP, sizeof(__pyx_k__EPOLLHUP), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLIN, __pyx_k__EPOLLIN, sizeof(__pyx_k__EPOLLIN), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLMSG, __pyx_k__EPOLLMSG, sizeof(__pyx_k__EPOLLMSG), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLOUT, __pyx_k__EPOLLOUT, sizeof(__pyx_k__EPOLLOUT), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLPRI, __pyx_k__EPOLLPRI, sizeof(__pyx_k__EPOLLPRI), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLRDBAND, __pyx_k__EPOLLRDBAND, sizeof(__pyx_k__EPOLLRDBAND), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLRDNORM, __pyx_k__EPOLLRDNORM, sizeof(__pyx_k__EPOLLRDNORM), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLWRBAND, __pyx_k__EPOLLWRBAND, sizeof(__pyx_k__EPOLLWRBAND), 0, 0, 1, 1}, + {&__pyx_n_s__EPOLLWRNORM, __pyx_k__EPOLLWRNORM, sizeof(__pyx_k__EPOLLWRNORM), 0, 0, 1, 1}, {&__pyx_n_s__ERR, __pyx_k__ERR, sizeof(__pyx_k__ERR), 0, 0, 1, 1}, {&__pyx_n_s__ET, __pyx_k__ET, sizeof(__pyx_k__ET), 0, 0, 1, 1}, {&__pyx_n_s__HUP, __pyx_k__HUP, sizeof(__pyx_k__HUP), 0, 0, 1, 1}, @@ -1446,11 +2083,8 @@ {&__pyx_n_s__WRNORM, __pyx_k__WRNORM, sizeof(__pyx_k__WRNORM), 0, 0, 1, 1}, {&__pyx_n_s____main__, __pyx_k____main__, sizeof(__pyx_k____main__), 0, 0, 1, 1}, {&__pyx_n_s____test__, __pyx_k____test__, sizeof(__pyx_k____test__), 0, 0, 1, 1}, - {&__pyx_n_s__append, __pyx_k__append, sizeof(__pyx_k__append), 0, 0, 1, 1}, - {&__pyx_n_s__data, __pyx_k__data, sizeof(__pyx_k__data), 0, 0, 1, 1}, {&__pyx_n_s__events, __pyx_k__events, sizeof(__pyx_k__events), 0, 0, 1, 1}, {&__pyx_n_s__fd, __pyx_k__fd, sizeof(__pyx_k__fd), 0, 0, 1, 1}, - {&__pyx_n_s__initialized, __pyx_k__initialized, sizeof(__pyx_k__initialized), 0, 0, 1, 1}, {&__pyx_n_s__maxevents, __pyx_k__maxevents, sizeof(__pyx_k__maxevents), 0, 0, 1, 1}, {&__pyx_n_s__op, __pyx_k__op, sizeof(__pyx_k__op), 0, 0, 1, 1}, {&__pyx_n_s__size, __pyx_k__size, sizeof(__pyx_k__size), 0, 0, 1, 1}, @@ -1458,13 +2092,14 @@ {0, 0, 0, 0, 0, 0, 0} }; static int __Pyx_InitCachedBuiltins(void) { - __pyx_builtin_IOError = __Pyx_GetName(__pyx_b, __pyx_n_s__IOError); if (!__pyx_builtin_IOError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 79; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_builtin_IOError = __Pyx_GetName(__pyx_b, __pyx_n_s__IOError); if (!__pyx_builtin_IOError) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 98; __pyx_clineno = __LINE__; goto __pyx_L1_error;} return 0; __pyx_L1_error:; return -1; } static int __Pyx_InitCachedConstants(void) { + __Pyx_RefNannyDeclarations __Pyx_RefNannySetupContext("__Pyx_InitCachedConstants"); __Pyx_RefNannyFinishContext(); return 0; @@ -1486,8 +2121,8 @@ #endif { PyObject *__pyx_t_1 = NULL; + __Pyx_RefNannyDeclarations #if CYTHON_REFNANNY - void* __pyx_refnanny = NULL; __Pyx_RefNanny = __Pyx_RefNannyImportAPI("refnanny"); if (!__Pyx_RefNanny) { PyErr_Clear(); @@ -1495,8 +2130,9 @@ if (!__Pyx_RefNanny) Py_FatalError("failed to import 'refnanny' module"); } - __pyx_refnanny = __Pyx_RefNanny->SetupContext("PyMODINIT_FUNC PyInit__epoll(void)", __LINE__, __FILE__); #endif + __Pyx_RefNannySetupContext("PyMODINIT_FUNC PyInit__epoll(void)"); + if ( __Pyx_check_binary_version() < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_empty_tuple = PyTuple_New(0); if (unlikely(!__pyx_empty_tuple)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_empty_bytes = PyBytes_FromStringAndSize("", 0); if (unlikely(!__pyx_empty_bytes)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} #ifdef __pyx_binding_PyCFunctionType_USED @@ -1532,180 +2168,232 @@ /*--- Constants init code ---*/ if (unlikely(__Pyx_InitCachedConstants() < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; __pyx_clineno = __LINE__; goto __pyx_L1_error;} /*--- Global init code ---*/ + /*--- Variable export code ---*/ /*--- Function export code ---*/ /*--- Type init code ---*/ - if (PyType_Ready(&__pyx_type_7twisted_6python_6_epoll_epoll) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;} - if (__Pyx_SetAttrString(__pyx_m, "epoll", (PyObject *)&__pyx_type_7twisted_6python_6_epoll_epoll) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyType_Ready(&__pyx_type_7twisted_6python_6_epoll_epoll) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + { + PyObject *wrapper = __Pyx_GetAttrString((PyObject *)&__pyx_type_7twisted_6python_6_epoll_epoll, "__init__"); if (unlikely(!wrapper)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (Py_TYPE(wrapper) == &PyWrapperDescr_Type) { + __pyx_wrapperbase_7twisted_6python_6_epoll_5epoll___init__ = *((PyWrapperDescrObject *)wrapper)->d_base; + __pyx_wrapperbase_7twisted_6python_6_epoll_5epoll___init__.doc = __pyx_doc_7twisted_6python_6_epoll_5epoll___init__; + ((PyWrapperDescrObject *)wrapper)->d_base = &__pyx_wrapperbase_7twisted_6python_6_epoll_5epoll___init__; + } + } + if (__Pyx_SetAttrString(__pyx_m, "epoll", (PyObject *)&__pyx_type_7twisted_6python_6_epoll_epoll) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __pyx_ptype_7twisted_6python_6_epoll_epoll = &__pyx_type_7twisted_6python_6_epoll_epoll; /*--- Type import code ---*/ + /*--- Variable import code ---*/ /*--- Function import code ---*/ /*--- Execution code ---*/ - /* "twisted/python/_epoll.pyx":165 - * free(events) + /* "twisted/python/_epoll.pyx":270 + * * * CTL_ADD = EPOLL_CTL_ADD # <<<<<<<<<<<<<< * CTL_DEL = EPOLL_CTL_DEL * CTL_MOD = EPOLL_CTL_MOD */ - __pyx_t_1 = PyInt_FromLong(EPOLL_CTL_ADD); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLL_CTL_ADD); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__CTL_ADD, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 165; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__CTL_ADD, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 270; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":166 + /* "twisted/python/_epoll.pyx":271 * * CTL_ADD = EPOLL_CTL_ADD * CTL_DEL = EPOLL_CTL_DEL # <<<<<<<<<<<<<< * CTL_MOD = EPOLL_CTL_MOD * */ - __pyx_t_1 = PyInt_FromLong(EPOLL_CTL_DEL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLL_CTL_DEL); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__CTL_DEL, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 166; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__CTL_DEL, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 271; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":167 + /* "twisted/python/_epoll.pyx":272 * CTL_ADD = EPOLL_CTL_ADD * CTL_DEL = EPOLL_CTL_DEL * CTL_MOD = EPOLL_CTL_MOD # <<<<<<<<<<<<<< * - * IN = EPOLLIN + * IN = EPOLLIN = c_EPOLLIN */ - __pyx_t_1 = PyInt_FromLong(EPOLL_CTL_MOD); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLL_CTL_MOD); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 272; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__CTL_MOD, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 167; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__CTL_MOD, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 272; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":169 + /* "twisted/python/_epoll.pyx":274 * CTL_MOD = EPOLL_CTL_MOD * - * IN = EPOLLIN # <<<<<<<<<<<<<< - * OUT = EPOLLOUT - * PRI = EPOLLPRI + * IN = EPOLLIN = c_EPOLLIN # <<<<<<<<<<<<<< + * OUT = EPOLLOUT = c_EPOLLOUT + * PRI = EPOLLPRI = c_EPOLLPRI */ - __pyx_t_1 = PyInt_FromLong(EPOLLIN); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLIN); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 274; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__IN, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 274; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLIN); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 274; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__IN, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 169; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLIN, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 274; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":170 + /* "twisted/python/_epoll.pyx":275 * - * IN = EPOLLIN - * OUT = EPOLLOUT # <<<<<<<<<<<<<< - * PRI = EPOLLPRI - * ERR = EPOLLERR + * IN = EPOLLIN = c_EPOLLIN + * OUT = EPOLLOUT = c_EPOLLOUT # <<<<<<<<<<<<<< + * PRI = EPOLLPRI = c_EPOLLPRI + * ERR = EPOLLERR = c_EPOLLERR */ - __pyx_t_1 = PyInt_FromLong(EPOLLOUT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLOUT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 275; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__OUT, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 170; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__OUT, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 275; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLOUT); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 275; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLOUT, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 275; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":171 - * IN = EPOLLIN - * OUT = EPOLLOUT - * PRI = EPOLLPRI # <<<<<<<<<<<<<< - * ERR = EPOLLERR - * HUP = EPOLLHUP + /* "twisted/python/_epoll.pyx":276 + * IN = EPOLLIN = c_EPOLLIN + * OUT = EPOLLOUT = c_EPOLLOUT + * PRI = EPOLLPRI = c_EPOLLPRI # <<<<<<<<<<<<<< + * ERR = EPOLLERR = c_EPOLLERR + * HUP = EPOLLHUP = c_EPOLLHUP */ - __pyx_t_1 = PyInt_FromLong(EPOLLPRI); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 171; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLPRI); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__PRI, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLPRI); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__PRI, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 171; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLPRI, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 276; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":172 - * OUT = EPOLLOUT - * PRI = EPOLLPRI - * ERR = EPOLLERR # <<<<<<<<<<<<<< - * HUP = EPOLLHUP - * ET = EPOLLET + /* "twisted/python/_epoll.pyx":277 + * OUT = EPOLLOUT = c_EPOLLOUT + * PRI = EPOLLPRI = c_EPOLLPRI + * ERR = EPOLLERR = c_EPOLLERR # <<<<<<<<<<<<<< + * HUP = EPOLLHUP = c_EPOLLHUP + * ET = EPOLLET = c_EPOLLET */ - __pyx_t_1 = PyInt_FromLong(EPOLLERR); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 172; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLERR); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 277; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ERR, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 277; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLERR); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 277; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ERR, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 172; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLERR, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 277; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":173 - * PRI = EPOLLPRI - * ERR = EPOLLERR - * HUP = EPOLLHUP # <<<<<<<<<<<<<< - * ET = EPOLLET + /* "twisted/python/_epoll.pyx":278 + * PRI = EPOLLPRI = c_EPOLLPRI + * ERR = EPOLLERR = c_EPOLLERR + * HUP = EPOLLHUP = c_EPOLLHUP # <<<<<<<<<<<<<< + * ET = EPOLLET = c_EPOLLET * */ - __pyx_t_1 = PyInt_FromLong(EPOLLHUP); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 173; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLHUP); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 278; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__HUP, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 173; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__HUP, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 278; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLHUP); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 278; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLHUP, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 278; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":174 - * ERR = EPOLLERR - * HUP = EPOLLHUP - * ET = EPOLLET # <<<<<<<<<<<<<< + /* "twisted/python/_epoll.pyx":279 + * ERR = EPOLLERR = c_EPOLLERR + * HUP = EPOLLHUP = c_EPOLLHUP + * ET = EPOLLET = c_EPOLLET # <<<<<<<<<<<<<< * - * RDNORM = EPOLLRDNORM + * RDNORM = EPOLLRDNORM = c_EPOLLRDNORM */ - __pyx_t_1 = PyInt_FromLong(EPOLLET); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLET); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 279; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ET, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 279; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLET); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 279; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__ET, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 174; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLET, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 279; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":176 - * ET = EPOLLET + /* "twisted/python/_epoll.pyx":281 + * ET = EPOLLET = c_EPOLLET * - * RDNORM = EPOLLRDNORM # <<<<<<<<<<<<<< - * RDBAND = EPOLLRDBAND - * WRNORM = EPOLLWRNORM + * RDNORM = EPOLLRDNORM = c_EPOLLRDNORM # <<<<<<<<<<<<<< + * RDBAND = EPOLLRDBAND = c_EPOLLRDBAND + * WRNORM = EPOLLWRNORM = c_EPOLLWRNORM */ - __pyx_t_1 = PyInt_FromLong(EPOLLRDNORM); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLRDNORM); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 281; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__RDNORM, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 281; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLRDNORM); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 281; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__RDNORM, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 176; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLRDNORM, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 281; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":177 + /* "twisted/python/_epoll.pyx":282 * - * RDNORM = EPOLLRDNORM - * RDBAND = EPOLLRDBAND # <<<<<<<<<<<<<< - * WRNORM = EPOLLWRNORM - * WRBAND = EPOLLWRBAND + * RDNORM = EPOLLRDNORM = c_EPOLLRDNORM + * RDBAND = EPOLLRDBAND = c_EPOLLRDBAND # <<<<<<<<<<<<<< + * WRNORM = EPOLLWRNORM = c_EPOLLWRNORM + * WRBAND = EPOLLWRBAND = c_EPOLLWRBAND */ - __pyx_t_1 = PyInt_FromLong(EPOLLRDBAND); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 177; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLRDBAND); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 282; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__RDBAND, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 177; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__RDBAND, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 282; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLRDBAND); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 282; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLRDBAND, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 282; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":178 - * RDNORM = EPOLLRDNORM - * RDBAND = EPOLLRDBAND - * WRNORM = EPOLLWRNORM # <<<<<<<<<<<<<< - * WRBAND = EPOLLWRBAND - * MSG = EPOLLMSG + /* "twisted/python/_epoll.pyx":283 + * RDNORM = EPOLLRDNORM = c_EPOLLRDNORM + * RDBAND = EPOLLRDBAND = c_EPOLLRDBAND + * WRNORM = EPOLLWRNORM = c_EPOLLWRNORM # <<<<<<<<<<<<<< + * WRBAND = EPOLLWRBAND = c_EPOLLWRBAND + * MSG = EPOLLMSG = c_EPOLLMSG */ - __pyx_t_1 = PyInt_FromLong(EPOLLWRNORM); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLWRNORM); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 283; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__WRNORM, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 283; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLWRNORM); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 283; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__WRNORM, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLWRNORM, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 283; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":179 - * RDBAND = EPOLLRDBAND - * WRNORM = EPOLLWRNORM - * WRBAND = EPOLLWRBAND # <<<<<<<<<<<<<< - * MSG = EPOLLMSG - * + /* "twisted/python/_epoll.pyx":284 + * RDBAND = EPOLLRDBAND = c_EPOLLRDBAND + * WRNORM = EPOLLWRNORM = c_EPOLLWRNORM + * WRBAND = EPOLLWRBAND = c_EPOLLWRBAND # <<<<<<<<<<<<<< + * MSG = EPOLLMSG = c_EPOLLMSG */ - __pyx_t_1 = PyInt_FromLong(EPOLLWRBAND); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 179; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLWRBAND); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__WRBAND, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLWRBAND); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__WRBAND, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 179; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLWRBAND, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 284; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; - /* "twisted/python/_epoll.pyx":180 - * WRNORM = EPOLLWRNORM - * WRBAND = EPOLLWRBAND - * MSG = EPOLLMSG # <<<<<<<<<<<<<< - * + /* "twisted/python/_epoll.pyx":285 + * WRNORM = EPOLLWRNORM = c_EPOLLWRNORM + * WRBAND = EPOLLWRBAND = c_EPOLLWRBAND + * MSG = EPOLLMSG = c_EPOLLMSG # <<<<<<<<<<<<<< */ - __pyx_t_1 = PyInt_FromLong(EPOLLMSG); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 180; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __pyx_t_1 = PyInt_FromLong(EPOLLMSG); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 285; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_GOTREF(__pyx_t_1); + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__MSG, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 285; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; + __pyx_t_1 = PyInt_FromLong(EPOLLMSG); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 285; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_GOTREF(__pyx_t_1); - if (PyObject_SetAttr(__pyx_m, __pyx_n_s__MSG, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 180; __pyx_clineno = __LINE__; goto __pyx_L1_error;} + if (PyObject_SetAttr(__pyx_m, __pyx_n_s__EPOLLMSG, __pyx_t_1) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 285; __pyx_clineno = __LINE__; goto __pyx_L1_error;} __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0; /* "twisted/python/_epoll.pyx":1 @@ -1721,7 +2409,7 @@ __pyx_L1_error:; __Pyx_XDECREF(__pyx_t_1); if (__pyx_m) { - __Pyx_AddTraceback("init twisted.python._epoll"); + __Pyx_AddTraceback("init twisted.python._epoll", __pyx_clineno, __pyx_lineno, __pyx_filename); Py_DECREF(__pyx_m); __pyx_m = 0; } else if (!PyErr_Occurred()) { PyErr_SetString(PyExc_ImportError, "init twisted.python._epoll"); @@ -1734,137 +2422,38 @@ return __pyx_m; #endif } - -/* Runtime support code */ + +/* Runtime support code */ + +#if CYTHON_REFNANNY +static __Pyx_RefNannyAPIStruct *__Pyx_RefNannyImportAPI(const char *modname) { + PyObject *m = NULL, *p = NULL; + void *r = NULL; + m = PyImport_ImportModule((char *)modname); + if (!m) goto end; + p = PyObject_GetAttrString(m, (char *)"RefNannyAPI"); + if (!p) goto end; + r = PyLong_AsVoidPtr(p); +end: + Py_XDECREF(p); + Py_XDECREF(m); + return (__Pyx_RefNannyAPIStruct *)r; +} +#endif /* CYTHON_REFNANNY */ static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) { PyObject *result; result = PyObject_GetAttr(dict, name); - if (!result) - PyErr_SetObject(PyExc_NameError, name); - return result; -} - -static void __Pyx_RaiseDoubleKeywordsError( - const char* func_name, - PyObject* kw_name) -{ - PyErr_Format(PyExc_TypeError, - #if PY_MAJOR_VERSION >= 3 - "%s() got multiple values for keyword argument '%U'", func_name, kw_name); - #else - "%s() got multiple values for keyword argument '%s'", func_name, - PyString_AS_STRING(kw_name)); - #endif -} - -static int __Pyx_ParseOptionalKeywords( - PyObject *kwds, - PyObject **argnames[], - PyObject *kwds2, - PyObject *values[], - Py_ssize_t num_pos_args, - const char* function_name) -{ - PyObject *key = 0, *value = 0; - Py_ssize_t pos = 0; - PyObject*** name; - PyObject*** first_kw_arg = argnames + num_pos_args; - - while (PyDict_Next(kwds, &pos, &key, &value)) { - name = first_kw_arg; - while (*name && (**name != key)) name++; - if (*name) { - values[name-argnames] = value; - } else { - #if PY_MAJOR_VERSION < 3 - if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) { - #else - if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) { - #endif - goto invalid_keyword_type; - } else { - for (name = first_kw_arg; *name; name++) { - #if PY_MAJOR_VERSION >= 3 - if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) && - PyUnicode_Compare(**name, key) == 0) break; - #else - if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) && - _PyString_Eq(**name, key)) break; - #endif - } - if (*name) { - values[name-argnames] = value; - } else { - /* unexpected keyword found */ - for (name=argnames; name != first_kw_arg; name++) { - if (**name == key) goto arg_passed_twice; - #if PY_MAJOR_VERSION >= 3 - if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) && - PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice; - #else - if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) && - _PyString_Eq(**name, key)) goto arg_passed_twice; - #endif - } - if (kwds2) { - if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; - } else { - goto invalid_keyword; - } - } - } + if (!result) { + if (dict != __pyx_b) { + PyErr_Clear(); + result = PyObject_GetAttr(__pyx_b, name); + } + if (!result) { + PyErr_SetObject(PyExc_NameError, name); } } - return 0; -arg_passed_twice: - __Pyx_RaiseDoubleKeywordsError(function_name, **name); - goto bad; -invalid_keyword_type: - PyErr_Format(PyExc_TypeError, - "%s() keywords must be strings", function_name); - goto bad; -invalid_keyword: - PyErr_Format(PyExc_TypeError, - #if PY_MAJOR_VERSION < 3 - "%s() got an unexpected keyword argument '%s'", - function_name, PyString_AsString(key)); - #else - "%s() got an unexpected keyword argument '%U'", - function_name, key); - #endif -bad: - return -1; -} - -static void __Pyx_RaiseArgtupleInvalid( - const char* func_name, - int exact, - Py_ssize_t num_min, - Py_ssize_t num_max, - Py_ssize_t num_found) -{ - Py_ssize_t num_expected; - const char *number, *more_or_less; - - if (num_found < num_min) { - num_expected = num_min; - more_or_less = "at least"; - } else { - num_expected = num_max; - more_or_less = "at most"; - } - if (exact) { - more_or_less = "exactly"; - } - number = (num_expected == 1) ? "" : "s"; - PyErr_Format(PyExc_TypeError, - #if PY_VERSION_HEX < 0x02050000 - "%s() takes %s %d positional argument%s (%d given)", - #else - "%s() takes %s %zd positional argument%s (%zd given)", - #endif - func_name, more_or_less, num_expected, number, num_found); + return result; } static CYTHON_INLINE void __Pyx_ErrRestore(PyObject *type, PyObject *value, PyObject *tb) { @@ -1895,7 +2484,8 @@ #if PY_MAJOR_VERSION < 3 -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { + /* cause is unused */ Py_XINCREF(type); Py_XINCREF(value); Py_XINCREF(tb); @@ -1962,7 +2552,7 @@ #else /* Python 3+ */ -static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) { +static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb, PyObject *cause) { if (tb == Py_None) { tb = 0; } else if (tb && !PyTraceBack_Check(tb)) { @@ -1987,6 +2577,29 @@ goto bad; } + if (cause) { + PyObject *fixed_cause; + if (PyExceptionClass_Check(cause)) { + fixed_cause = PyObject_CallObject(cause, NULL); + if (fixed_cause == NULL) + goto bad; + } + else if (PyExceptionInstance_Check(cause)) { + fixed_cause = cause; + Py_INCREF(fixed_cause); + } + else { + PyErr_SetString(PyExc_TypeError, + "exception causes must derive from " + "BaseException"); + goto bad; + } + if (!value) { + value = PyObject_CallObject(type, NULL); + } + PyException_SetCause(value, fixed_cause); + } + PyErr_SetObject(type, value); if (tb) { @@ -2004,6 +2617,124 @@ } #endif +static void __Pyx_RaiseDoubleKeywordsError( + const char* func_name, + PyObject* kw_name) +{ + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION >= 3 + "%s() got multiple values for keyword argument '%U'", func_name, kw_name); + #else + "%s() got multiple values for keyword argument '%s'", func_name, + PyString_AS_STRING(kw_name)); + #endif +} + +static int __Pyx_ParseOptionalKeywords( + PyObject *kwds, + PyObject **argnames[], + PyObject *kwds2, + PyObject *values[], + Py_ssize_t num_pos_args, + const char* function_name) +{ + PyObject *key = 0, *value = 0; + Py_ssize_t pos = 0; + PyObject*** name; + PyObject*** first_kw_arg = argnames + num_pos_args; + + while (PyDict_Next(kwds, &pos, &key, &value)) { + name = first_kw_arg; + while (*name && (**name != key)) name++; + if (*name) { + values[name-argnames] = value; + } else { + #if PY_MAJOR_VERSION < 3 + if (unlikely(!PyString_CheckExact(key)) && unlikely(!PyString_Check(key))) { + #else + if (unlikely(!PyUnicode_CheckExact(key)) && unlikely(!PyUnicode_Check(key))) { + #endif + goto invalid_keyword_type; + } else { + for (name = first_kw_arg; *name; name++) { + #if PY_MAJOR_VERSION >= 3 + if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) && + PyUnicode_Compare(**name, key) == 0) break; + #else + if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) && + _PyString_Eq(**name, key)) break; + #endif + } + if (*name) { + values[name-argnames] = value; + } else { + /* unexpected keyword found */ + for (name=argnames; name != first_kw_arg; name++) { + if (**name == key) goto arg_passed_twice; + #if PY_MAJOR_VERSION >= 3 + if (PyUnicode_GET_SIZE(**name) == PyUnicode_GET_SIZE(key) && + PyUnicode_Compare(**name, key) == 0) goto arg_passed_twice; + #else + if (PyString_GET_SIZE(**name) == PyString_GET_SIZE(key) && + _PyString_Eq(**name, key)) goto arg_passed_twice; + #endif + } + if (kwds2) { + if (unlikely(PyDict_SetItem(kwds2, key, value))) goto bad; + } else { + goto invalid_keyword; + } + } + } + } + } + return 0; +arg_passed_twice: + __Pyx_RaiseDoubleKeywordsError(function_name, **name); + goto bad; +invalid_keyword_type: + PyErr_Format(PyExc_TypeError, + "%s() keywords must be strings", function_name); + goto bad; +invalid_keyword: + PyErr_Format(PyExc_TypeError, + #if PY_MAJOR_VERSION < 3 + "%s() got an unexpected keyword argument '%s'", + function_name, PyString_AsString(key)); + #else + "%s() got an unexpected keyword argument '%U'", + function_name, key); + #endif +bad: + return -1; +} + +static void __Pyx_RaiseArgtupleInvalid( + const char* func_name, + int exact, + Py_ssize_t num_min, + Py_ssize_t num_max, + Py_ssize_t num_found) +{ + Py_ssize_t num_expected; + const char *more_or_less; + + if (num_found < num_min) { + num_expected = num_min; + more_or_less = "at least"; + } else { + num_expected = num_max; + more_or_less = "at most"; + } + if (exact) { + more_or_less = "exactly"; + } + PyErr_Format(PyExc_TypeError, + "%s() takes %s %"PY_FORMAT_SIZE_T"d positional argument%s (%"PY_FORMAT_SIZE_T"d given)", + func_name, more_or_less, num_expected, + (num_expected == 1) ? "" : "s", num_found); +} + static CYTHON_INLINE unsigned char __Pyx_PyInt_AsUnsignedChar(PyObject* x) { const unsigned char neg_one = (unsigned char)-1, const_zero = 0; const int is_unsigned = neg_one > const_zero; @@ -2215,9 +2946,9 @@ "can't convert negative value to unsigned long"); return (unsigned long)-1; } - return PyLong_AsUnsignedLong(x); + return (unsigned long)PyLong_AsUnsignedLong(x); } else { - return PyLong_AsLong(x); + return (unsigned long)PyLong_AsLong(x); } } else { unsigned long val; @@ -2250,9 +2981,9 @@ "can't convert negative value to unsigned PY_LONG_LONG"); return (unsigned PY_LONG_LONG)-1; } - return PyLong_AsUnsignedLongLong(x); + return (unsigned PY_LONG_LONG)PyLong_AsUnsignedLongLong(x); } else { - return PyLong_AsLongLong(x); + return (unsigned PY_LONG_LONG)PyLong_AsLongLong(x); } } else { unsigned PY_LONG_LONG val; @@ -2285,9 +3016,9 @@ "can't convert negative value to long"); return (long)-1; } - return PyLong_AsUnsignedLong(x); + return (long)PyLong_AsUnsignedLong(x); } else { - return PyLong_AsLong(x); + return (long)PyLong_AsLong(x); } } else { long val; @@ -2320,9 +3051,9 @@ "can't convert negative value to PY_LONG_LONG"); return (PY_LONG_LONG)-1; } - return PyLong_AsUnsignedLongLong(x); + return (PY_LONG_LONG)PyLong_AsUnsignedLongLong(x); } else { - return PyLong_AsLongLong(x); + return (PY_LONG_LONG)PyLong_AsLongLong(x); } } else { PY_LONG_LONG val; @@ -2355,9 +3086,9 @@ "can't convert negative value to signed long"); return (signed long)-1; } - return PyLong_AsUnsignedLong(x); + return (signed long)PyLong_AsUnsignedLong(x); } else { - return PyLong_AsLong(x); + return (signed long)PyLong_AsLong(x); } } else { signed long val; @@ -2390,9 +3121,9 @@ "can't convert negative value to signed PY_LONG_LONG"); return (signed PY_LONG_LONG)-1; } - return PyLong_AsUnsignedLongLong(x); + return (signed PY_LONG_LONG)PyLong_AsUnsignedLongLong(x); } else { - return PyLong_AsLongLong(x); + return (signed PY_LONG_LONG)PyLong_AsLongLong(x); } } else { signed PY_LONG_LONG val; @@ -2404,11 +3135,31 @@ } } +static int __Pyx_check_binary_version(void) { + char ctversion[4], rtversion[4]; + PyOS_snprintf(ctversion, 4, "%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION); + PyOS_snprintf(rtversion, 4, "%s", Py_GetVersion()); + if (ctversion[0] != rtversion[0] || ctversion[2] != rtversion[2]) { + char message[200]; + PyOS_snprintf(message, sizeof(message), + "compiletime version %s of module '%.100s' " + "does not match runtime version %s", + ctversion, __Pyx_MODULE_NAME, rtversion); + #if PY_VERSION_HEX < 0x02050000 + return PyErr_Warn(NULL, message); + #else + return PyErr_WarnEx(NULL, message, 1); + #endif + } + return 0; +} + #include "compile.h" #include "frameobject.h" #include "traceback.h" -static void __Pyx_AddTraceback(const char *funcname) { +static void __Pyx_AddTraceback(const char *funcname, int __pyx_clineno, + int __pyx_lineno, const char *__pyx_filename) { PyObject *py_srcfile = 0; PyObject *py_funcname = 0; PyObject *py_globals = 0; diff -Nru twisted-12.0.0/twisted/python/_epoll.pyx twisted-12.2.0/twisted/python/_epoll.pyx --- twisted-12.0.0/twisted/python/_epoll.pyx 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/python/_epoll.pyx 2012-02-19 19:24:21.000000000 +0000 @@ -34,17 +34,17 @@ EPOLL_CTL_MOD = 3 cdef enum EPOLL_EVENTS: - EPOLLIN = 0x001 - EPOLLPRI = 0x002 - EPOLLOUT = 0x004 - EPOLLRDNORM = 0x040 - EPOLLRDBAND = 0x080 - EPOLLWRNORM = 0x100 - EPOLLWRBAND = 0x200 - EPOLLMSG = 0x400 - EPOLLERR = 0x008 - EPOLLHUP = 0x010 - EPOLLET = (1 << 31) + c_EPOLLIN "EPOLLIN" = 0x001 + c_EPOLLPRI "EPOLLPRI" = 0x002 + c_EPOLLOUT "EPOLLOUT" = 0x004 + c_EPOLLRDNORM "EPOLLRDNORM" = 0x040 + c_EPOLLRDBAND "EPOLLRDBAND" = 0x080 + c_EPOLLWRNORM "EPOLLWRNORM" = 0x100 + c_EPOLLWRBAND "EPOLLWRBAND" = 0x200 + c_EPOLLMSG "EPOLLMSG" = 0x400 + c_EPOLLERR "EPOLLERR" = 0x008 + c_EPOLLHUP "EPOLLHUP" = 0x010 + c_EPOLLET "EPOLLET" = (1 << 31) ctypedef union epoll_data_t: void *ptr @@ -65,6 +65,44 @@ cdef extern PyThreadState *PyEval_SaveThread() cdef extern void PyEval_RestoreThread(PyThreadState*) +cdef call_epoll_wait(int fd, unsigned int maxevents, int timeout_msec): + """ + Wait for an I/O event, wrap epoll_wait(2). + + @type fd: C{int} + @param fd: The epoll file descriptor number. + + @type maxevents: C{int} + @param maxevents: Maximum number of events returned. + + @type timeout_msec: C{int} + @param timeout_msec: Maximum time in milliseconds waiting for events. 0 + makes it return immediately whereas -1 makes it wait indefinitely. + + @raise IOError: Raised if the underlying epoll_wait() call fails. + """ + cdef epoll_event *events + cdef int result + cdef int nbytes + cdef PyThreadState *_save + + nbytes = sizeof(epoll_event) * maxevents + events = malloc(nbytes) + memset(events, 0, nbytes) + try: + _save = PyEval_SaveThread() + result = epoll_wait(fd, events, maxevents, timeout_msec) + PyEval_RestoreThread(_save) + + if result == -1: + raise IOError(errno, strerror(errno)) + results = [] + for i from 0 <= i < result: + results.append((events[i].data.fd, events[i].events)) + return results + finally: + free(events) + cdef class epoll: """ Represent a set of file descriptors being monitored for events. @@ -73,7 +111,10 @@ cdef int fd cdef int initialized - def __init__(self, int size): + def __init__(self, int size=1023): + """ + The constructor arguments are compatible with select.poll.__init__. + """ self.fd = epoll_create(size) if self.fd == -1: raise IOError(errno, strerror(errno)) @@ -99,10 +140,79 @@ """ return self.fd + def register(self, int fd, int events): + """ + Add (register) a file descriptor to be monitored by self. + + This method is compatible with select.epoll.register in Python 2.6. + + Wrap epoll_ctl(2). + + @type fd: C{int} + @param fd: File descriptor to modify + + @type events: C{int} + @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET. + + @raise IOError: Raised if the underlying epoll_ctl() call fails. + """ + cdef int result + cdef epoll_event evt + evt.events = events + evt.data.fd = fd + result = epoll_ctl(self.fd, CTL_ADD, fd, &evt) + if result == -1: + raise IOError(errno, strerror(errno)) + + def unregister(self, int fd): + """ + Remove (unregister) a file descriptor monitored by self. + + This method is compatible with select.epoll.unregister in Python 2.6. + + Wrap epoll_ctl(2). + + @type fd: C{int} + @param fd: File descriptor to modify + + @raise IOError: Raised if the underlying epoll_ctl() call fails. + """ + cdef int result + cdef epoll_event evt + # We don't have to fill evt.events for CTL_DEL. + evt.data.fd = fd + result = epoll_ctl(self.fd, CTL_DEL, fd, &evt) + if result == -1: + raise IOError(errno, strerror(errno)) + + def modify(self, int fd, int events): + """ + Modify the modified state of a file descriptor monitored by self. + + This method is compatible with select.epoll.modify in Python 2.6. + + Wrap epoll_ctl(2). + + @type fd: C{int} + @param fd: File descriptor to modify + + @type events: C{int} + @param events: A bit set of IN, OUT, PRI, ERR, HUP, and ET. + + @raise IOError: Raised if the underlying epoll_ctl() call fails. + """ + cdef int result + cdef epoll_event evt + evt.events = events + evt.data.fd = fd + result = epoll_ctl(self.fd, CTL_MOD, fd, &evt) + if result == -1: + raise IOError(errno, strerror(errno)) + def _control(self, int op, int fd, int events): """ Modify the monitored state of a particular file descriptor. - + Wrap epoll_ctl(2). @type op: C{int} @@ -132,50 +242,44 @@ @param maxevents: Maximum number of events returned. @type timeout: C{int} + @param timeout: Maximum time in milliseconds waiting for events. 0 + makes it return immediately whereas -1 makes it wait indefinitely. + + @raise IOError: Raised if the underlying epoll_wait() call fails. + """ + return call_epoll_wait(self.fd, maxevents, timeout) + + def poll(self, float timeout=-1, unsigned int maxevents=1024): + """ + Wait for an I/O event, wrap epoll_wait(2). + + This method is compatible with select.epoll.poll in Python 2.6. + + @type maxevents: C{int} + @param maxevents: Maximum number of events returned. + + @type timeout: C{int} @param timeout: Maximum time waiting for events. 0 makes it return immediately whereas -1 makes it wait indefinitely. - + @raise IOError: Raised if the underlying epoll_wait() call fails. """ - cdef epoll_event *events - cdef int result - cdef int nbytes - cdef int fd - cdef PyThreadState *_save - - nbytes = sizeof(epoll_event) * maxevents - events = malloc(nbytes) - memset(events, 0, nbytes) - try: - fd = self.fd - - _save = PyEval_SaveThread() - result = epoll_wait(fd, events, maxevents, timeout) - PyEval_RestoreThread(_save) + return call_epoll_wait(self.fd, maxevents, (timeout * 1000.0)) - if result == -1: - raise IOError(errno, strerror(errno)) - results = [] - for i from 0 <= i < result: - results.append((events[i].data.fd, events[i].events)) - return results - finally: - free(events) CTL_ADD = EPOLL_CTL_ADD CTL_DEL = EPOLL_CTL_DEL CTL_MOD = EPOLL_CTL_MOD -IN = EPOLLIN -OUT = EPOLLOUT -PRI = EPOLLPRI -ERR = EPOLLERR -HUP = EPOLLHUP -ET = EPOLLET - -RDNORM = EPOLLRDNORM -RDBAND = EPOLLRDBAND -WRNORM = EPOLLWRNORM -WRBAND = EPOLLWRBAND -MSG = EPOLLMSG - +IN = EPOLLIN = c_EPOLLIN +OUT = EPOLLOUT = c_EPOLLOUT +PRI = EPOLLPRI = c_EPOLLPRI +ERR = EPOLLERR = c_EPOLLERR +HUP = EPOLLHUP = c_EPOLLHUP +ET = EPOLLET = c_EPOLLET + +RDNORM = EPOLLRDNORM = c_EPOLLRDNORM +RDBAND = EPOLLRDBAND = c_EPOLLRDBAND +WRNORM = EPOLLWRNORM = c_EPOLLWRNORM +WRBAND = EPOLLWRBAND = c_EPOLLWRBAND +MSG = EPOLLMSG = c_EPOLLMSG diff -Nru twisted-12.0.0/twisted/python/_release.py twisted-12.2.0/twisted/python/_release.py --- twisted-12.0.0/twisted/python/_release.py 2011-11-20 15:23:17.000000000 +0000 +++ twisted-12.2.0/twisted/python/_release.py 2012-08-12 16:48:05.000000000 +0000 @@ -25,6 +25,7 @@ from twisted.python.versions import Version from twisted.python.filepath import FilePath from twisted.python.dist import twisted_subprojects +from twisted.python.compat import execfile # This import is an example of why you shouldn't use this module unless you're # radix @@ -947,7 +948,8 @@ """ from twisted.python.dist import twisted_subprojects as subprojects - def __init__(self, rootDirectory, outputDirectory, apiBaseURL=None): + def __init__(self, rootDirectory, outputDirectory, templatePath=None, + apiBaseURL=None): """ Create a distribution builder. @@ -958,6 +960,10 @@ @param outputDirectory: The directory in which to create the tarballs. @type outputDirectory: L{FilePath} + @param templatePath: Path to the template file that is used for the + howto documentation. + @type templatePath: L{FilePath} + @type apiBaseURL: C{str} or C{NoneType} @param apiBaseURL: A format string which will be interpolated with the fully-qualified Python name for each API link. For example, to @@ -966,6 +972,7 @@ """ self.rootDirectory = rootDirectory self.outputDirectory = outputDirectory + self.templatePath = templatePath self.apiBaseURL = apiBaseURL self.manBuilder = ManBuilder() self.docBuilder = DocBuilder() @@ -985,14 +992,15 @@ @param howtoPath: The "resource path" as L{DocBuilder} describes it. @type howtoPath: L{FilePath} """ - templatePath = self.rootDirectory.child("doc").child("core" - ).child("howto").child("template.tpl") + if self.templatePath is None: + self.templatePath = self.rootDirectory.descendant( + ["doc", "core", "howto", "template.tpl"]) if path.basename() == "man": self.manBuilder.build(path) if path.isdir(): try: self.docBuilder.build(version, howtoPath, path, - templatePath, self.apiBaseURL, True) + self.templatePath, self.apiBaseURL, True) except NoDocumentsFound: pass @@ -1041,7 +1049,8 @@ submodule.basename())) for docDir in self.rootDirectory.child("doc").children(): - tarball.add(docDir.path, buildPath("doc", docDir.basename())) + if docDir.basename() != "historic": + tarball.add(docDir.path, buildPath("doc", docDir.basename())) for toplevel in self.rootDirectory.children(): if not toplevel.isdir(): @@ -1187,13 +1196,15 @@ """ + class NotWorkingDirectory(Exception): """ Raised when a directory does not appear to be an SVN working directory. """ -def buildAllTarballs(checkout, destination): + +def buildAllTarballs(checkout, destination, templatePath=None): """ Build complete tarballs (including documentation) for Twisted and all subprojects. @@ -1206,10 +1217,13 @@ will be exported. @type destination: L{FilePath} @param destination: The directory in which tarballs will be placed. + @type templatePath: L{FilePath} + @param templatePath: Location of the template file that is used for the + howto documentation. - @raise UncleanWorkingDirectory: if there are modifications to the + @raise UncleanWorkingDirectory: If there are modifications to the working directory of C{checkout}. - @raise NotWorkingDirectory: if the checkout path is not an SVN checkout. + @raise NotWorkingDirectory: If the C{checkout} path is not an SVN checkout. """ if not checkout.child(".svn").exists(): raise NotWorkingDirectory( @@ -1218,7 +1232,7 @@ if runCommand(["svn", "st", checkout.path]).strip(): raise UncleanWorkingDirectory( "There are local modifications to the SVN checkout in %s." - % (checkout.path,)) + % (checkout.path,)) workPath = FilePath(mkdtemp()) export = workPath.child("export") @@ -1231,7 +1245,8 @@ versionString) if not destination.exists(): destination.createDirectory() - db = DistributionBuilder(export, destination, apiBaseURL=apiBaseURL) + db = DistributionBuilder(export, destination, templatePath=templatePath, + apiBaseURL=apiBaseURL) db.buildCore(versionString) for subproject in twisted_subprojects: @@ -1295,14 +1310,23 @@ """ Build all release tarballs. - @type args: list of str + @type args: list of C{str} @param args: The command line arguments to process. This must contain - two strings: the checkout directory and the destination directory. - """ - if len(args) != 2: - sys.exit("Must specify two arguments: " - "Twisted checkout and destination path") - self.buildAllTarballs(FilePath(args[0]), FilePath(args[1])) + at least two strings: the checkout directory and the destination + directory. An optional third string can be specified for the website + template file, used for building the howto documentation. If this + string isn't specified, the default template included in twisted + will be used. + """ + if len(args) < 2 or len(args) > 3: + sys.exit("Must specify at least two arguments: " + "Twisted checkout and destination path. The optional third " + "argument is the website template path.") + if len(args) == 2: + self.buildAllTarballs(FilePath(args[0]), FilePath(args[1])) + elif len(args) == 3: + self.buildAllTarballs(FilePath(args[0]), FilePath(args[1]), + FilePath(args[2])) diff -Nru twisted-12.0.0/twisted/python/compat.py twisted-12.2.0/twisted/python/compat.py --- twisted-12.0.0/twisted/python/compat.py 2011-06-03 22:55:35.000000000 +0000 +++ twisted-12.2.0/twisted/python/compat.py 2012-07-14 21:49:36.000000000 +0000 @@ -139,12 +139,12 @@ 'set_connect_state', 'set_accept_state', 'connect_ex', 'sendall'): - exec """def %s(self, *args): + exec("""def %s(self, *args): self._lock.acquire() try: return apply(self._ssl_conn.%s, args) finally: - self._lock.release()\n""" % (f, f) + self._lock.release()\n""" % (f, f)) sys.modules['OpenSSL.tsafe'] = tsafe import operator @@ -175,3 +175,34 @@ from functools import reduce except ImportError: reduce = reduce + + + +def execfile(filename, globals, locals=None): + """ + Execute a Python script in the given namespaces. + + Similar to the execfile builtin, but a namespace is mandatory, partly + because that's a sensible thing to require, and because otherwise we'd + have to do some frame hacking. + + This is a compatibility implementation for Python 3 porting, to avoid the + use of the deprecated builtin C{execfile} function. + """ + if locals is None: + locals = globals + fin = open(filename, "rbU") + try: + source = fin.read() + finally: + fin.close() + code = compile(source, filename, "exec") + exec(code, globals, locals) + + +__all__ = [ + "execfile", + "frozenset", + "reduce", + "set", + ] diff -Nru twisted-12.0.0/twisted/python/components.py twisted-12.2.0/twisted/python/components.py --- twisted-12.0.0/twisted/python/components.py 2011-08-20 12:54:04.000000000 +0000 +++ twisted-12.2.0/twisted/python/components.py 2012-06-07 13:15:27.000000000 +0000 @@ -28,9 +28,6 @@ interface. """ -# system imports -import warnings - # zope3 imports from zope.interface import interface, declarations from zope.interface.adapter import AdapterRegistry @@ -40,11 +37,6 @@ from twisted.persisted import styles -class ComponentsDeprecationWarning(DeprecationWarning): - """ - Nothing emits this warning anymore. - """ - # Twisted's global adapter registry globalRegistry = AdapterRegistry() @@ -143,27 +135,6 @@ _addHook(globalRegistry) -## backwardsCompatImplements and fixClassImplements should probably stick around for another -## release cycle. No harm doing so in any case. - -def backwardsCompatImplements(klass): - """DEPRECATED. - - Does nothing. Previously handled backwards compat from a - zope.interface using class to a class wanting old twisted - components interface behaviors. - """ - warnings.warn("components.backwardsCompatImplements doesn't do anything in Twisted 2.3, stop calling it.", ComponentsDeprecationWarning, stacklevel=2) - -def fixClassImplements(klass): - """DEPRECATED. - - Does nothing. Previously converted class from __implements__ to - zope implementation. - """ - warnings.warn("components.fixClassImplements doesn't do anything in Twisted 2.3, stop calling it.", ComponentsDeprecationWarning, stacklevel=2) - - def getRegistry(): """Returns the Twisted global C{zope.interface.adapter.AdapterRegistry} instance. @@ -311,7 +282,7 @@ True on your adapter class. """ k = reflect.qual(interface) - if self._adapterCache.has_key(k): + if k in self._adapterCache: return self._adapterCache[k] else: adapter = interface.__adapt__(self) @@ -461,12 +432,7 @@ __all__ = [ # Sticking around: - "ComponentsDeprecationWarning", "registerAdapter", "getAdapterFactory", "Adapter", "Componentized", "ReprableComponentized", "getRegistry", "proxyForInterface", - - # Deprecated: - "backwardsCompatImplements", - "fixClassImplements", ] diff -Nru twisted-12.0.0/twisted/python/constants.py twisted-12.2.0/twisted/python/constants.py --- twisted-12.0.0/twisted/python/constants.py 2011-12-10 21:39:18.000000000 +0000 +++ twisted-12.2.0/twisted/python/constants.py 2012-03-11 09:04:58.000000000 +0000 @@ -7,10 +7,12 @@ numeric, and bit flag values. """ -__all__ = ['NamedConstant', 'ValueConstant', 'Names', 'Values'] +__all__ = [ + 'NamedConstant', 'ValueConstant', 'FlagConstant', + 'Names', 'Values', 'Flags'] from itertools import count - +from operator import and_, or_, xor _unspecified = object() _constantOrder = count().next @@ -124,8 +126,9 @@ if isinstance(descriptor, cls._constantType): constants.append((descriptor._index, name, descriptor)) enumerants = {} + constants.sort() for (index, enumerant, descriptor) in constants: - value = cls._constantFactory(enumerant) + value = cls._constantFactory(enumerant, descriptor) descriptor._realize(cls, enumerant, value) enumerants[enumerant] = descriptor # Replace the _enumerants descriptor with the result so future @@ -137,7 +140,7 @@ _initializeEnumerants = classmethod(_initializeEnumerants) - def _constantFactory(cls, name): + def _constantFactory(cls, name, descriptor): """ Construct the value for a new constant to add to this container. @@ -243,3 +246,132 @@ return constant raise ValueError(value) lookupByValue = classmethod(lookupByValue) + + + +def _flagOp(op, left, right): + """ + Implement a binary operator for a L{FlagConstant} instance. + + @param op: A two-argument callable implementing the binary operation. For + example, C{operator.or_}. + + @param left: The left-hand L{FlagConstant} instance. + @param right: The right-hand L{FlagConstant} instance. + + @return: A new L{FlagConstant} instance representing the result of the + operation. + """ + value = op(left.value, right.value) + names = op(left.names, right.names) + result = FlagConstant() + result._realize(left._container, names, value) + return result + + + +class FlagConstant(_Constant): + """ + L{FlagConstant} defines an attribute to be a flag constant within a + collection defined by a L{Flags} subclass. + + L{FlagConstant} is only for use in the definition of L{Flags} subclasses. + Do not instantiate L{FlagConstant} elsewhere and do not subclass it. + """ + def __init__(self, value=_unspecified): + _Constant.__init__(self) + self.value = value + + + def _realize(self, container, names, value): + """ + Complete the initialization of this L{FlagConstant}. + + This implementation differs from other C{_realize} implementations in + that a L{FlagConstant} may have several names which apply to it, due to + flags being combined with various operators. + + @param container: The L{Flags} subclass this constant is part of. + + @param names: When a single-flag value is being initialized, a C{str} + giving the name of that flag. This is the case which happens when a + L{Flags} subclass is being initialized and L{FlagConstant} instances + from its body are being realized. Otherwise, a C{set} of C{str} + giving names of all the flags set on this L{FlagConstant} instance. + This is the case when two flags are combined using C{|}, for + example. + """ + if isinstance(names, str): + name = names + names = set([names]) + elif len(names) == 1: + (name,) = names + else: + name = "{" + ",".join(sorted(names)) + "}" + _Constant._realize(self, container, name, value) + self.value = value + self.names = names + + + def __or__(self, other): + """ + Define C{|} on two L{FlagConstant} instances to create a new + L{FlagConstant} instance with all flags set in either instance set. + """ + return _flagOp(or_, self, other) + + + def __and__(self, other): + """ + Define C{&} on two L{FlagConstant} instances to create a new + L{FlagConstant} instance with only flags set in both instances set. + """ + return _flagOp(and_, self, other) + + + def __xor__(self, other): + """ + Define C{^} on two L{FlagConstant} instances to create a new + L{FlagConstant} instance with only flags set on exactly one instance + set. + """ + return _flagOp(xor, self, other) + + + def __invert__(self): + """ + Define C{~} on a L{FlagConstant} instance to create a new + L{FlagConstant} instance with all flags not set on this instance set. + """ + result = FlagConstant() + result._realize(self._container, set(), 0) + for flag in self._container.iterconstants(): + if flag.value & self.value == 0: + result |= flag + return result + + + +class Flags(Values): + """ + A L{Flags} subclass contains constants which can be combined using the + common bitwise operators (C{|}, C{&}, etc) similar to a I{bitvector} from a + language like C. + """ + _constantType = FlagConstant + + _value = 1 + + def _constantFactory(cls, name, descriptor): + """ + For L{FlagConstant} instances with no explicitly defined value, assign + the next power of two as its value. + """ + if descriptor.value is _unspecified: + value = cls._value + cls._value <<= 1 + else: + value = descriptor.value + cls._value = value << 1 + return value + _constantFactory = classmethod(_constantFactory) diff -Nru twisted-12.0.0/twisted/python/dist.py twisted-12.2.0/twisted/python/dist.py --- twisted-12.0.0/twisted/python/dist.py 2011-11-20 15:19:42.000000000 +0000 +++ twisted-12.2.0/twisted/python/dist.py 2012-07-25 19:04:04.000000000 +0000 @@ -1,3 +1,7 @@ +# -*- test-case-name: twisted.python.test.test_dist -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + """ Distutils convenience functionality. @@ -15,6 +19,8 @@ import platform import sys +from twisted.python.compat import execfile + twisted_subprojects = ["conch", "lore", "mail", "names", "news", "pair", "runner", "web", @@ -208,6 +214,25 @@ return result +def getExtensions(): + """ + Get all extensions from core and all subprojects. + """ + extensions = [] + + if not sys.platform.startswith('java'): + for dir in os.listdir("twisted") + [""]: + topfiles = os.path.join("twisted", dir, "topfiles") + if os.path.isdir(topfiles): + ns = {} + setup_py = os.path.join(topfiles, "setup.py") + execfile(setup_py, ns, ns) + if "extensions" in ns: + extensions.extend(ns["extensions"]) + + return extensions + + def getPackages(dname, pkgname=None, results=None, ignore=None, parent=None): """ Get all packages which are under dname. This is necessary for @@ -261,26 +286,27 @@ ## Helpers and distutil tweaks class build_scripts_twisted(build_scripts.build_scripts): - """Renames scripts so they end with '.py' on Windows.""" - + """ + Renames scripts so they end with '.py' on Windows. + """ def run(self): build_scripts.build_scripts.run(self) if not os.name == "nt": return for f in os.listdir(self.build_dir): - fpath=os.path.join(self.build_dir, f) + fpath = os.path.join(self.build_dir, f) if not fpath.endswith(".py"): - try: - os.unlink(fpath + ".py") - except EnvironmentError, e: - if e.args[1]=='No such file or directory': - pass - os.rename(fpath, fpath + ".py") + pypath = fpath + ".py" + if os.path.exists(pypath): + os.unlink(pypath) + os.rename(fpath, pypath) class install_data_twisted(install_data.install_data): - """I make sure data files are installed in the package directory.""" + """ + I make sure data files are installed in the package directory. + """ def finalize_options(self): self.set_undefined_options('install', ('install_lib', 'install_dir') diff -Nru twisted-12.0.0/twisted/python/filepath.py twisted-12.2.0/twisted/python/filepath.py --- twisted-12.0.0/twisted/python/filepath.py 2011-07-01 23:37:45.000000000 +0000 +++ twisted-12.2.0/twisted/python/filepath.py 2012-06-07 13:15:27.000000000 +0000 @@ -36,6 +36,8 @@ from twisted.python.util import FancyEqMixin +from zope.interface import Interface, Attribute, implements + _CREATE_FLAGS = (os.O_EXCL | os.O_CREAT | os.O_RDWR | @@ -79,6 +81,133 @@ randomBytes = getattr(os, 'urandom', _stub_urandom) armor = getattr(base64, 'urlsafe_b64encode', _stub_armor) +class IFilePath(Interface): + """ + File path object. + + A file path represents a location for a file-like-object and can be + organized into a hierarchy; a file path can can children which are + themselves file paths. + + A file path has a name which unique identifies it in the context of its + parent (if it has one); a file path can not have two children with the same + name. This name is referred to as the file path's "base name". + + A series of such names can be used to locate nested children of a file path; + such a series is referred to as the child's "path", relative to the parent. + In this case, each name in the path is referred to as a "path segment"; the + child's base name is the segment in the path. + + When representing a file path as a string, a "path separator" is used to + delimit the path segments within the string. For a file system path, that + would be C{os.sep}. + + Note that the values of child names may be restricted. For example, a file + system path will not allow the use of the path separator in a name, and + certain names (eg. C{"."} and C{".."}) may be reserved or have special + meanings. + + @since: 12.1 + """ + sep = Attribute("The path separator to use in string representations") + + def child(name): + """ + Obtain a direct child of this file path. The child may or may not + exist. + + @param name: the name of a child of this path. C{name} must be a direct + child of this path and may not contain a path separator. + @return: the child of this path with the given C{name}. + @raise InsecurePath: if C{name} describes a file path that is not a + direct child of this file path. + """ + + def open(mode="r"): + """ + Opens this file path with the given mode. + @return: a file-like-object. + @raise Exception: if this file path cannot be opened. + """ + + def changed(): + """ + Clear any cached information about the state of this path on disk. + """ + + def getsize(): + """ + @return: the size of the file at this file path in bytes. + @raise Exception: if the size cannot be obtained. + """ + + def getModificationTime(): + """ + Retrieve the time of last access from this file. + + @return: a number of seconds from the epoch. + @rtype: float + """ + + def getStatusChangeTime(): + """ + Retrieve the time of the last status change for this file. + + @return: a number of seconds from the epoch. + @rtype: float + """ + + def getAccessTime(): + """ + Retrieve the time that this file was last accessed. + + @return: a number of seconds from the epoch. + @rtype: float + """ + + def exists(): + """ + @return: C{True} if the file at this file path exists, C{False} + otherwise. + """ + + def isdir(): + """ + @return: C{True} if the file at this file path is a directory, C{False} + otherwise. + """ + + def isfile(): + """ + @return: C{True} if the file at this file path is a regular file, + C{False} otherwise. + """ + + def children(): + """ + @return: a sequence of the children of the directory at this file path. + @raise Exception: if the file at this file path is not a directory. + """ + + def basename(): + """ + @return: the base name of this file path. + """ + + def parent(): + """ + A file path for the directory containing the file at this file path. + """ + + def sibling(name): + """ + A file path for the directory containing the file at this file path. + @param name: the name of a sibling of this path. C{name} must be a direct + sibling of this path and may not contain a path separator. + + @return: a sibling file path of this one. + """ + class InsecurePath(Exception): """ Error that is raised when the path provided to FilePath is invalid. @@ -136,10 +265,13 @@ -class _PathHelper: +class AbstractFilePath(object): """ - Abstract helper class also used by ZipPath; implements certain utility - methods. + Abstract implementation of an IFilePath; must be completed by a subclass. + + This class primarily exists to provide common implementations of certain + methods in IFilePath. It is *not* a required parent class for IFilePath + implementations, just a useful starting point. """ def getContent(self): @@ -433,7 +565,7 @@ -class FilePath(_PathHelper): +class FilePath(AbstractFilePath): """ I am a path on the filesystem that only permits 'downwards' access. @@ -479,9 +611,13 @@ @type statinfo: C{int} or L{types.NoneType} or L{os.stat_result} """ + implements(IFilePath) + statinfo = None path = None + sep = slash + def __init__(self, path, alwaysCreate=False): """ Convert a path string to an absolute path if necessary and initialize @@ -496,7 +632,7 @@ returning everything else. """ d = self.__dict__.copy() - if d.has_key('statinfo'): + if 'statinfo' in d: del d['statinfo'] return d @@ -517,7 +653,7 @@ # Catch paths like C:blah that don't have a slash raise InsecurePath("%r contains a colon." % (path,)) norm = normpath(path) - if slash in norm: + if self.sep in norm: raise InsecurePath("%r contains one or more directory separators" % (path,)) newpath = abspath(joinpath(self.path, norm)) if not newpath.startswith(self.path): @@ -652,6 +788,9 @@ @param reraise: a boolean. If true, re-raise exceptions from L{os.stat}; otherwise, mark this path as not existing, and remove any cached stat information. + + @raise Exception: is C{reraise} is C{True} and an exception occurs while + reloading metadata. """ try: self.statinfo = stat(self.path) @@ -734,7 +873,7 @@ def getInodeNumber(self): """ - Retrieve the file serial number, also called inode number, which + Retrieve the file serial number, also called inode number, which distinguishes this file from all other files on the same device. @raise: NotImplementedError if the platform is Windows, since the @@ -907,7 +1046,7 @@ """ Returns whether the underlying path is a block device. - @return: C{True} if it is a block device, C{False} otherwise + @return: C{True} if it is a block device, C{False} otherwise @rtype: C{bool} @since: 11.1 """ @@ -924,7 +1063,7 @@ """ Returns whether the underlying path is a socket. - @return: C{True} if it is a socket, C{False} otherwise + @return: C{True} if it is a socket, C{False} otherwise @rtype: C{bool} @since: 11.1 """ @@ -983,7 +1122,12 @@ def touch(self): """ - Update the access and modified times of the L{FilePath}'s file. + Updates the access and last modification times of the file at this + file path to the current time. Also creates the file if it does not + already exist. + + @raise Exception: if unable to create or modify the last modification + time of the file. """ try: self.open('a').close() @@ -996,8 +1140,7 @@ """ Removes the file or directory that is represented by self. If C{self.path} is a directory, recursively remove all its children - before removing the directory. If it's a file or link, just delete - it. + before removing the directory. If it's a file or link, just delete it. """ if self.isdir() and not self.islink(): for child in self.children(): @@ -1023,7 +1166,7 @@ pattern. """ import glob - path = self.path[-1] == '/' and self.path + pattern or slash.join([self.path, pattern]) + path = self.path[-1] == '/' and self.path + pattern or self.sep.join([self.path, pattern]) return map(self.clonePath, glob.glob(path)) @@ -1111,8 +1254,6 @@ os.rename(sib.path, self.path) - # new in 2.2.0 - def __cmp__(self, other): if not isinstance(other, FilePath): return NotImplemented diff -Nru twisted-12.0.0/twisted/python/formmethod.py twisted-12.2.0/twisted/python/formmethod.py --- twisted-12.0.0/twisted/python/formmethod.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/python/formmethod.py 2012-08-01 11:08:41.000000000 +0000 @@ -59,7 +59,7 @@ def coerce(self, val): """Convert the value to the correct format.""" - raise NotImplementedError, "implement in subclass" + raise NotImplementedError("implement in subclass") class String(Argument): @@ -79,9 +79,9 @@ def coerce(self, val): s = str(val) if len(s) < self.min: - raise InputError, "Value must be at least %s characters long" % self.min + raise InputError("Value must be at least %s characters long" % self.min) if self.max != None and len(s) > self.max: - raise InputError, "Value must be at most %s characters long" % self.max + raise InputError("Value must be at most %s characters long" % self.max) return str(val) @@ -100,12 +100,12 @@ def coerce(self, vals): if len(vals) != 2 or vals[0] != vals[1]: - raise InputError, "Please enter the same password twice." + raise InputError("Please enter the same password twice.") s = str(vals[0]) if len(s) < self.min: - raise InputError, "Value must be at least %s characters long" % self.min + raise InputError("Value must be at least %s characters long" % self.min) if self.max != None and len(s) > self.max: - raise InputError, "Value must be at most %s characters long" % self.max + raise InputError("Value must be at most %s characters long" % self.max) return s @@ -137,7 +137,7 @@ try: return int(val) except ValueError: - raise InputError, "%s is not valid, please enter a whole number, e.g. 10" % val + raise InputError("%s is not valid, please enter a whole number, e.g. 10" % val) class IntegerRange(Integer): @@ -154,9 +154,9 @@ if self.allowNone and result == None: return result if result < self.min: - raise InputError, "Value %s is too small, it should be at least %s" % (result, self.min) + raise InputError("Value %s is too small, it should be at least %s" % (result, self.min)) if result > self.max: - raise InputError, "Value %s is too large, it should be at most %s" % (result, self.max) + raise InputError("Value %s is too large, it should be at most %s" % (result, self.max)) return result @@ -181,7 +181,7 @@ try: return float(val) except ValueError: - raise InputError, "Invalid float: %s" % val + raise InputError("Invalid float: %s" % val) class Choice(Argument): @@ -258,8 +258,8 @@ class File(Argument): def __init__(self, name, allowNone=1, shortDesc=None, longDesc=None, hints=None): - self.allowNone = allowNone - Argument.__init__(self, name, None, shortDesc, longDesc, hints) + Argument.__init__(self, name, None, shortDesc, longDesc, hints, + allowNone=allowNone) def coerce(self, file): if not file and self.allowNone: @@ -267,7 +267,7 @@ elif file: return file else: - raise InputError, "Invalid File" + raise InputError("Invalid File") def positiveInt(x): x = int(x) @@ -294,18 +294,18 @@ try: year, month, day = map(positiveInt, args) except ValueError: - raise InputError, "Invalid date" + raise InputError("Invalid date") if (month, day) == (2, 29): if not calendar.isleap(year): - raise InputError, "%d was not a leap year" % year + raise InputError("%d was not a leap year" % year) else: return year, month, day try: mdays = calendar.mdays[month] except IndexError: - raise InputError, "Invalid date" + raise InputError("Invalid date") if day > mdays: - raise InputError, "Invalid date" + raise InputError("Invalid date") return year, month, day diff -Nru twisted-12.0.0/twisted/python/hook.py twisted-12.2.0/twisted/python/hook.py --- twisted-12.0.0/twisted/python/hook.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/python/hook.py 2012-08-12 15:28:29.000000000 +0000 @@ -32,11 +32,8 @@ values and exception status of the main method will be propogated (assuming none of the hooks raise an exception). Hooks will be executed in the order in which they are added. - """ -# System Imports -import string ### Public Interface @@ -98,8 +95,10 @@ def _XXX(k,n,s): - "string manipulation garbage" - x = s % (string.replace(k.__module__,'.','_'), k.__name__, n) + """ + String manipulation garbage. + """ + x = s % (k.__module__.replace('.', '_'), k.__name__, n) return x def PRE(k,n): diff -Nru twisted-12.0.0/twisted/python/log.py twisted-12.2.0/twisted/python/log.py --- twisted-12.0.0/twisted/python/log.py 2011-08-14 01:01:36.000000000 +0000 +++ twisted-12.2.0/twisted/python/log.py 2012-07-15 06:48:04.000000000 +0000 @@ -22,10 +22,10 @@ class ILogContext: """ - Actually, this interface is just a synoym for the dictionary interface, + Actually, this interface is just a synonym for the dictionary interface, but it serves as a key for the default information in a log. - I do not inherit from Interface because the world is a cruel place. + I do not inherit from C{Interface} because the world is a cruel place. """ @@ -93,85 +93,6 @@ _keptErrors = [] _ignoreErrors = [] -def startKeepingErrors(): - """ - DEPRECATED in Twisted 2.5. - - Support function for testing frameworks. - - Start keeping errors in a buffer which can be retrieved (and emptied) with - flushErrors. - """ - warnings.warn("log.startKeepingErrors is deprecated since Twisted 2.5", - category=DeprecationWarning, stacklevel=2) - global _keepErrors - _keepErrors = 1 - - -def flushErrors(*errorTypes): - """ - DEPRECATED in Twisted 2.5. See L{TestCase.flushLoggedErrors}. - - Support function for testing frameworks. - - Return a list of errors that occurred since the last call to flushErrors(). - (This will return None unless startKeepingErrors has been called.) - """ - - warnings.warn("log.flushErrors is deprecated since Twisted 2.5. " - "If you need to flush errors from within a unittest, " - "use TestCase.flushLoggedErrors instead.", - category=DeprecationWarning, stacklevel=2) - return _flushErrors(*errorTypes) - - -def _flushErrors(*errorTypes): - """ - PRIVATE. DEPRECATED. DON'T USE. - """ - global _keptErrors - k = _keptErrors - _keptErrors = [] - if errorTypes: - for erk in k: - shouldReLog = 1 - for errT in errorTypes: - if erk.check(errT): - shouldReLog = 0 - if shouldReLog: - err(erk) - return k - -def ignoreErrors(*types): - """ - DEPRECATED - """ - warnings.warn("log.ignoreErrors is deprecated since Twisted 2.5", - category=DeprecationWarning, stacklevel=2) - _ignore(*types) - -def _ignore(*types): - """ - PRIVATE. DEPRECATED. DON'T USE. - """ - for type in types: - _ignoreErrors.append(type) - -def clearIgnores(): - """ - DEPRECATED - """ - warnings.warn("log.clearIgnores is deprecated since Twisted 2.5", - category=DeprecationWarning, stacklevel=2) - _clearIgnores() - -def _clearIgnores(): - """ - PRIVATE. DEPRECATED. DON'T USE. - """ - global _ignoreErrors - _ignoreErrors = [] - def err(_stuff=None, _why=None, **kw): """ diff -Nru twisted-12.0.0/twisted/python/otp.py twisted-12.2.0/twisted/python/otp.py --- twisted-12.0.0/twisted/python/otp.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/python/otp.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,496 +0,0 @@ -# -*- test-case-name: twisted.python.test.test_otp -*- -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -A One-Time Password System based on RFC 2289 - -The class Authenticator contains the hashing-logic, and the parser for the -readable output. It also contains challenge which returns a string describing -the authentication scheme for a client. - -OTP is a password container for an user on a server. - -NOTE: Does not take care of transmitting the shared secret password. - -At the end there's a dict called dict which is dictionary contain 2048 -words for storing pronouncable 11-bit values. Taken from RFC 1760. - -Uses the MD5- and SHA-algorithms for hashing - -Todo: RFC2444, SASL (perhaps), parsing hex-responses - -This module is deprecated. Consider using U{another Python OTP -library} instead. -""" - -import warnings -import string -import random - -warnings.warn( - "twisted.python.otp is deprecated since Twisted 8.3.", - category=DeprecationWarning, - stacklevel=2) - - -def stringToLong(s): - """ Convert digest to long """ - result = 0L - for byte in s: - result = (256 * result) + ord(byte) - return result - -def stringToDWords(s): - """ Convert digest to a list of four 32-bits words """ - result = [] - for a in xrange(len(s) / 4): - tmp = 0L - for byte in s[-4:]: - tmp = (256 * tmp) + ord(byte) - result.append(tmp) - s = s[:-4] - return result - -def longToString(l): - """ Convert long to digest """ - result = "" - while l > 0L: - result = chr(l % 256) + result - l = l / 256L - return result - -from twisted.python.hashlib import md5, sha1 -hashid = {md5: 'md5', sha1: 'sha1'} - -INITIALSEQUENCE = 1000 -MINIMUMSEQUENCE = 50 - -class Unauthorized(Exception): - """the Unauthorized exception - - This exception is raised when an action is not allowed, or a user is not - authenticated properly. - """ - -class OTPAuthenticator: - """ - A One Time Password System - - Based on RFC 2289, which is based on a the S/KEY Authentication-scheme. - It uses the MD5- and SHA-algorithms for hashing - - The variable OTP is at all times a 64bit string. - - @ivar hash: An object which can be used to compute hashes. This is either - L{md5} or L{sha1}. - """ - def __init__(self, hash = md5): - "Set the hash to either md5 or sha1" - self.hash = hash - - - def generateSeed(self): - "Return a 10 char random seed, with 6 lowercase chars and 4 digits" - seed = '' - for x in range(6): - seed = seed + chr(random.randrange(97,122)) - for x in range(4): - seed = seed + chr(random.randrange(48,57)) - return seed - - def foldDigest(self, otp): - if self.hash == md5: - return self.foldDigest128(otp) - if self.hash == sha1: - return self.foldDigest160(otp) - - def foldDigest128(self, otp128): - "Fold a 128 bit digest to 64 bit" - regs = stringToDWords(otp128) - p0 = regs[0] ^ regs[2] - p1 = regs[1] ^ regs[3] - S = '' - for a in xrange(4): - S = chr(p0 & 0xFF) + S - p0 = p0 >> 8 - for a in xrange(4): - S = chr(p1 & 0xFF) + S - p1 = p1 >> 8 - return S - - def foldDigest160(self, otp160): - "Fold a 160 bit digest to 64 bit" - regs = stringToDWords(otp160) - p0 = regs[0] ^ regs[2] - p1 = regs[1] ^ regs[3] - p0 = regs[0] ^ regs[4] - S = '' - for a in xrange(4): - S = chr(p0 & 0xFF) + S - p0 = p0 >> 8 - for a in xrange(4): - S = chr(p1 & 0xFF) + S - p1 = p1 >> 8 - return S - - def hashUpdate(self, digest): - "Run through the hash and fold to 64 bit" - h = self.hash(digest) - return self.foldDigest(h.digest()) - - def generateOTP(self, seed, passwd, sequence): - """Return a 64 bit OTP based on inputs - Run through makeReadable to get a 6 word pass-phrase""" - seed = string.lower(seed) - otp = self.hashUpdate(seed + passwd) - for a in xrange(sequence): - otp = self.hashUpdate(otp) - return otp - - def calculateParity(self, otp): - "Calculate the parity from a 64bit OTP" - parity = 0 - for i in xrange(0, 64, 2): - parity = parity + otp & 0x3 - otp = otp >> 2 - return parity - - def makeReadable(self, otp): - "Returns a 6 word pass-phrase from a 64bit OTP" - digest = stringToLong(otp) - list = [] - parity = self.calculateParity(digest) - for i in xrange(4,-1, -1): - list.append(dict[(digest >> (i * 11 + 9)) & 0x7FF]) - list.append(dict[(digest << 2) & 0x7FC | (parity & 0x03)]) - return string.join(list) - - def challenge(self, seed, sequence): - """Return a challenge in the format otp- """ - return "otp-%s %i %s" % (hashid[self.hash], sequence, seed) - - def parsePhrase(self, phrase): - """Decode the phrase, and return a 64bit OTP - I will raise Unauthorized if the parity is wrong - TODO: Add support for hex (MUST) and the '2nd scheme'(SHOULD)""" - words = string.split(phrase) - for i in xrange(len(words)): - words[i] = string.upper(words[i]) - b = 0L - for i in xrange(0,5): - b = b | ((long(dict.index(words[i])) << ((4-i)*11L+9L))) - tmp = dict.index(words[5]) - b = b | (tmp & 0x7FC ) >> 2 - if (tmp & 3) <> self.calculateParity(b): - raise Unauthorized("Parity error") - digest = longToString(b) - return digest - -class OTP(OTPAuthenticator): - """An automatic version of the OTP-Authenticator - - Updates the sequence and the keeps last approved password on success - On the next authentication, the stored password is hashed and checked - up against the one given by the user. If they match, the sequencecounter - is decreased and the circle is closed. - - This object should be glued to each user - - Note: - It does NOT reset the sequence when the combinations left approach zero, - This has to be done manuelly by instancing a new object - """ - seed = None - sequence = 0 - lastotp = None - - def __init__(self, passwd, sequence = INITIALSEQUENCE, hash=md5): - """Initialize the OTP-Sequence, and discard the password""" - OTPAuthenticator.__init__(self, hash) - seed = self.generateSeed() - # Generate the 'last' password - self.lastotp = OTPAuthenticator.generateOTP(self, seed, passwd, sequence+1) - self.seed = seed - self.sequence = sequence - - def challenge(self): - """Return a challenge string""" - result = OTPAuthenticator.challenge(self, self.seed, self.sequence) - return result - - def authenticate(self, phrase): - """Test the phrase against the last challenge issued""" - try: - digest = self.parsePhrase(phrase) - hasheddigest = self.hashUpdate(digest) - if (self.lastotp == hasheddigest): - self.lastotp = digest - if self.sequence > MINIMUMSEQUENCE: - self.sequence = self.sequence - 1 - return "ok" - else: - raise Unauthorized("Failed") - except Unauthorized, msg: - raise Unauthorized(msg) - -# -# The 2048 word standard dictionary from RFC 1760 -# -dict = ["A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", -"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", -"AN", "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS", -"APT", "ARC", "ARE", "ARK", "ARM", "ART", "AS", "ASH", -"ASK", "AT", "ATE", "AUG", "AUK", "AVE", "AWE", "AWK", -"AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM", -"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", -"BEN", "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT", -"BOB", "BOG", "BON", "BOO", "BOP", "BOW", "BOY", "BUB", -"BUD", "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY", -"BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT", -"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", -"COW", "COY", "CRY", "CUB", "CUE", "CUP", "CUR", "CUT", -"DAB", "DAD", "DAM", "DAN", "DAR", "DAY", "DEE", "DEL", -"DEN", "DES", "DEW", "DID", "DIE", "DIG", "DIN", "DIP", -"DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB", -"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", -"EGG", "EGO", "ELI", "ELK", "ELM", "ELY", "EM", "END", -"EST", "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN", -"FAR", "FAT", "FAY", "FED", "FEE", "FEW", "FIB", "FIG", -"FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR", -"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", -"GAM", "GAP", "GAS", "GAY", "GEE", "GEL", "GEM", "GET", -"GIG", "GIL", "GIN", "GO", "GOT", "GUM", "GUN", "GUS", -"GUT", "GUY", "GYM", "GYP", "HA", "HAD", "HAL", "HAM", -"HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", -"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", -"HIS", "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP", -"HOT", "HOW", "HUB", "HUE", "HUG", "HUH", "HUM", "HUT", -"I", "ICY", "IDA", "IF", "IKE", "ILL", "INK", "INN", -"IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", -"ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", -"JAY", "JET", "JIG", "JIM", "JO", "JOB", "JOE", "JOG", -"JOT", "JOY", "JUG", "JUT", "KAY", "KEG", "KEN", "KEY", -"KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD", -"LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", -"LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", -"LIP", "LIT", "LO", "LOB", "LOG", "LOP", "LOS", "LOT", -"LOU", "LOW", "LOY", "LUG", "LYE", "MA", "MAC", "MAD", -"MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY", "ME", -"MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", -"MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", -"MUD", "MUG", "MUM", "MY", "NAB", "NAG", "NAN", "NAP", -"NAT", "NAY", "NE", "NED", "NEE", "NET", "NEW", "NIB", -"NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR", -"NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", -"OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", -"OH", "OIL", "OK", "OLD", "ON", "ONE", "OR", "ORB", -"ORE", "ORR", "OS", "OTT", "OUR", "OUT", "OVA", "OW", -"OWE", "OWL", "OWN", "OX", "PA", "PAD", "PAL", "PAM", -"PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", -"PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", -"PIN", "PIT", "PLY", "PO", "POD", "POE", "POP", "POT", -"POW", "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT", -"QUO", "RAG", "RAM", "RAN", "RAP", "RAT", "RAW", "RAY", -"REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", -"RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", -"ROY", "RUB", "RUE", "RUG", "RUM", "RUN", "RYE", "SAC", -"SAD", "SAG", "SAL", "SAM", "SAN", "SAP", "SAT", "SAW", -"SAY", "SEA", "SEC", "SEE", "SEN", "SET", "SEW", "SHE", -"SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", -"SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", -"SPA", "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", -"TAB", "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED", -"TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM", "TIN", -"TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", -"TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", -"UN", "UP", "US", "USE", "VAN", "VAT", "VET", "VIE", -"WAD", "WAG", "WAR", "WAS", "WAY", "WE", "WEB", "WED", -"WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK", "WON", -"WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", -"YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", -"ABUT", "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", -"ADDS", "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", -"AIDE", "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", -"ALIA", "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", -"AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", -"ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", -"AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", -"ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", -"AVOW", "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", -"BAIL", "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", -"BALM", "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", -"BARK", "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", -"BATH", "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", -"BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER", "BEET", "BELA", -"BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT", "BESS", -"BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", "BILE", -"BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB", -"BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE", -"BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY", -"BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA", -"BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", "BOOM", "BOON", -"BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", "BOTH", "BOUT", -"BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", "BRAY", "BRED", -"BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF", "BULB", -"BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", "BURN", -"BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE", -"CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM", -"CAME", "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", "CART", -"CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", "CELL", "CENT", -"CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", "CHEN", "CHEW", -"CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", "CHUM", "CITE", -"CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", "CLOD", "CLOG", -"CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK", "COCO", -"CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA", -"COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON", -"COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL", -"CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD", -"CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", "CURB", "CURD", -"CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", "DAME", "DANA", -"DANE", "DANG", "DANK", "DARE", "DARK", "DARN", "DART", "DASH", -"DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", "DEAD", "DEAF", -"DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM", "DEER", -"DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE", -"DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT", -"DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL", -"DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE", -"DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", "DRAM", "DRAW", -"DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", "DUCT", "DUEL", -"DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", "DUSK", "DUST", -"DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", "EASY", "EBEN", -"ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", "EDNA", "EGAN", -"ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS", -"ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT", -"FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG", -"FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL", -"FEET", "FELL", "FELT", "FEND", "FERN", "FEST", "FEUD", "FIEF", -"FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", "FINK", "FIRE", -"FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", "FLAG", "FLAK", -"FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", "FLIT", "FLOC", -"FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", "FOGY", "FOIL", -"FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD", -"FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL", -"FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM", -"FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS", -"GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", "GALE", "GALL", -"GALT", "GAME", "GANG", "GARB", "GARY", "GASH", "GATE", "GAUL", -"GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", "GENT", "GERM", -"GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", "GINA", "GIRD", -"GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB", "GLOB", -"GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT", -"GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF", -"GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY", -"GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW", -"GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", "GUST", "GWEN", -"GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", "HALE", "HALF", -"HALL", "HALO", "HALT", "HAND", "HANG", "HANK", "HANS", "HARD", -"HARK", "HARM", "HART", "HASH", "HAST", "HATE", "HATH", "HAUL", -"HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT", "HEBE", -"HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", "HERB", -"HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE", -"HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS", -"HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT", -"HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN", -"HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", "HOYT", "HUCK", -"HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", "HULL", "HUNK", -"HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", "HYMN", "IBIS", -"ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO", "IONS", -"IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", "ITEM", -"IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN", -"JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE", -"JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE", -"JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", "JUJU", "JUKE", -"JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", "JUTE", "KAHN", -"KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", "KEEN", "KENO", -"KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", "KIND", "KING", -"KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT", "KNOB", -"KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE", -"LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE", -"LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS", -"LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD", -"LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", "LEFT", "LEND", -"LENS", "LENT", "LEON", "LESK", "LESS", "LEST", "LETS", "LIAR", -"LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", "LIFE", "LIFT", -"LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", "LIME", "LIND", -"LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE", "LOAD", -"LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA", -"LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE", -"LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE", -"LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH", -"LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", "MADE", "MAGI", -"MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", "MALL", "MALT", -"MANA", "MANN", "MANY", "MARC", "MARE", "MARK", "MARS", "MART", -"MARY", "MASH", "MASK", "MASS", "MAST", "MATE", "MATH", "MAUL", -"MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", "MEET", "MELD", -"MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE", -"MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND", -"MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE", -"MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL", -"MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", "MOOR", "MOOT", -"MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", "MOVE", "MUCH", -"MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", "MUSH", "MUST", -"MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", "NAIR", "NAME", -"NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", "NEAT", "NECK", -"NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS", -"NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH", -"NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE", -"NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY", -"OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", "OLAF", "OLDY", -"OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", "ONES", "ONLY", -"ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", "OTTO", "OUCH", -"OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", "OWNS", "QUAD", -"QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE", "RAID", -"RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE", -"RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED", -"REEF", "REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT", -"REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME", -"RING", "RINK", "RISE", "RISK", "RITE", "ROAD", "ROAM", "ROAR", -"ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", "ROOD", "ROOF", -"ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", "ROSY", "ROTH", -"ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", "RUDE", "RUDY", -"RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH", "RUSK", -"RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", "SAIL", -"SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK", -"SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT", -"SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN", -"SEES", "SELF", "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG", -"SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", "SHOD", "SHOE", -"SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", "SIFT", "SIGH", -"SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", "SING", "SINK", -"SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID", "SKIM", -"SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", "SLEW", -"SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG", -"SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB", -"SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL", -"SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", "SORT", "SOUL", -"SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", "STAY", "STEM", -"STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", "SUDS", "SUIT", -"SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", "SWAB", "SWAG", -"SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK", "TACT", -"TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE", -"TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET", -"TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN", -"THAT", "THEE", "THEM", "THEN", "THEY", "THIN", "THIS", "THUD", -"THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", "TILE", "TILL", -"TILT", "TIME", "TINA", "TINE", "TINT", "TINY", "TIRE", "TOAD", -"TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", "TONY", "TOOK", -"TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", "TOUT", "TOWN", -"TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM", "TRIO", -"TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT", -"TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN", -"TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH", -"VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA", -"VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", "VETO", "VICE", -"VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", "WACK", "WADE", -"WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", "WALL", "WALT", -"WAND", "WANE", "WANG", "WANT", "WARD", "WARM", "WARN", "WART", -"WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", "WAYS", "WEAK", -"WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL", -"WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE", -"WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL", -"WIND", "WINE", "WING", "WINK", "WINO", "WIRE", "WISE", "WISH", -"WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", "WORE", "WORK", -"WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG", "YANK", -"YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", "YELL", "YOGA", -"YOKE"] diff -Nru twisted-12.0.0/twisted/python/randbytes.py twisted-12.2.0/twisted/python/randbytes.py --- twisted-12.0.0/twisted/python/randbytes.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/python/randbytes.py 2012-04-01 20:07:59.000000000 +0000 @@ -33,12 +33,11 @@ You shouldn't have to instantiate this class, use the module level functions instead: it is an implementation detail and could be removed or changed arbitrarily. - - @cvar randomSources: list of file sources used when os.urandom is not - available. - @type randomSources: C{tuple} """ - randomSources = ('/dev/urandom',) + + # This variable is no longer used, and will eventually be removed. + randomSources = () + getrandbits = getrandbits @@ -52,26 +51,6 @@ raise SourceNotAvailable(e) - def _fileUrandom(self, nbytes): - """ - Wrapper around random file sources. - - This method isn't meant to be call out of the class and could be - removed arbitrarily. - """ - for src in self.randomSources: - try: - f = file(src, 'rb') - except (IOError, OSError): - pass - else: - bytes = f.read(nbytes) - f.close() - return bytes - raise SourceNotAvailable("File sources not available: %s" % - (self.randomSources,)) - - def secureRandom(self, nbytes, fallback=False): """ Return a number of secure random bytes. @@ -85,11 +64,11 @@ @return: a string of random bytes. @rtype: C{str} """ - for src in ("_osUrandom", "_fileUrandom"): - try: - return getattr(self, src)(nbytes) - except SourceNotAvailable: - pass + try: + return self._osUrandom(nbytes) + except SourceNotAvailable: + pass + if fallback: warnings.warn( "urandom unavailable - " diff -Nru twisted-12.0.0/twisted/python/rebuild.py twisted-12.2.0/twisted/python/rebuild.py --- twisted-12.0.0/twisted/python/rebuild.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/python/rebuild.py 2012-06-07 13:15:27.000000000 +0000 @@ -176,7 +176,7 @@ values.update(classes) values.update(functions) - fromOldModule = values.has_key + fromOldModule = values.__contains__ newclasses = newclasses.keys() classes = classes.keys() functions = functions.keys() diff -Nru twisted-12.0.0/twisted/python/reflect.py twisted-12.2.0/twisted/python/reflect.py --- twisted-12.0.0/twisted/python/reflect.py 2011-03-27 01:37:18.000000000 +0000 +++ twisted-12.2.0/twisted/python/reflect.py 2012-03-07 19:55:14.000000000 +0000 @@ -30,7 +30,7 @@ from StringIO import StringIO from twisted.python.util import unsignedID -from twisted.python.deprecate import deprecated +from twisted.python.deprecate import deprecated, deprecatedModuleAttribute from twisted.python.deprecate import _fullyQualifiedName as fullyQualifiedName from twisted.python.versions import Version @@ -44,6 +44,12 @@ where you don't want to name a variable, but you do want to set some attributes; for example, C{X()(y=z,a=b)}. """ + + deprecatedModuleAttribute( + Version("Twisted", 12, 1, 0), + "Settable is old and untested. Please write your own version of this " + "functionality if you need it.", "twisted.python.reflect", "Settable") + def __init__(self, **kw): self(**kw) @@ -54,7 +60,8 @@ class AccessorType(type): - """Metaclass that generates properties automatically. + """ + Metaclass that generates properties automatically. This is for Python 2.2 and up. @@ -75,6 +82,12 @@ """ + deprecatedModuleAttribute( + Version("Twisted", 12, 1, 0), + "AccessorType is old and untested. Please write your own version of " + "this functionality if you need it.", "twisted.python.reflect", + "AccessorType") + def __init__(self, name, bases, d): type.__init__(self, name, bases, d) accessors = {} @@ -111,7 +124,8 @@ class PropertyAccessor(object): - """A mixin class for Python 2.2 that uses AccessorType. + """ + A mixin class for Python 2.2 that uses AccessorType. This provides compatability with the pre-2.2 Accessor mixin, up to a point. @@ -138,6 +152,11 @@ # caused by it. # -- itamar + deprecatedModuleAttribute( + Version("Twisted", 12, 1, 0), + "PropertyAccessor is old and untested. Please write your own version " + "of this functionality if you need it.", "twisted.python.reflect", + "PropertyAccessor") __metaclass__ = AccessorType def reallySet(self, k, v): @@ -159,6 +178,11 @@ This implementation is for Python 2.1. """ + deprecatedModuleAttribute( + Version("Twisted", 12, 1, 0), + "Accessor is an implementation for Python 2.1 which is no longer " + "supported by Twisted.", "twisted.python.reflect", "Accessor") + def __setattr__(self, k,v): kstring='set_%s'%k if hasattr(self.__class__,kstring): @@ -199,6 +223,10 @@ # just in case OriginalAccessor = Accessor +deprecatedModuleAttribute( + Version("Twisted", 12, 1, 0), + "OriginalAccessor is a reference to class twisted.python.reflect.Accessor " + "which is deprecated.", "twisted.python.reflect", "OriginalAccessor") class Summer(Accessor): @@ -214,6 +242,11 @@ incremented, similiarly for the debit versions. """ + deprecatedModuleAttribute( + Version("Twisted", 12, 1, 0), + "Summer is a child class of twisted.python.reflect.Accessor which is " + "deprecated.", "twisted.python.reflect", "Summer") + def reallySet(self, k,v): "This method does the work." for sum in self.sums: @@ -245,7 +278,9 @@ class QueueMethod: - """ I represent a method that doesn't exist yet.""" + """ + I represent a method that doesn't exist yet. + """ def __init__(self, name, calls): self.name = name self.calls = calls @@ -294,7 +329,9 @@ def qual(clazz): - """Return full import path of a class.""" + """ + Return full import path of a class. + """ return clazz.__module__ + '.' + clazz.__name__ @@ -308,8 +345,10 @@ def getClass(obj): - """Return the class or type of object 'obj'. - Returns sensible result for oldstyle and newstyle instances and types.""" + """ + Return the class or type of object 'obj'. + Returns sensible result for oldstyle and newstyle instances and types. + """ if hasattr(obj, '__class__'): return obj.__class__ else: @@ -335,7 +374,9 @@ def namedModule(name): - """Return a module given its name.""" + """ + Return a module given its name. + """ topLevel = __import__(name) packages = name.split(".")[1:] m = topLevel @@ -345,7 +386,8 @@ def namedObject(name): - """Get a fully named module-global object. + """ + Get a fully named module-global object. """ classSplit = name.split('.') module = namedModule('.'.join(classSplit[:-1])) @@ -478,46 +520,6 @@ -def macro(name, filename, source, **identifiers): - """macro(name, source, **identifiers) - - This allows you to create macro-like behaviors in python. - """ - if not identifiers.has_key('name'): - identifiers['name'] = name - source = source % identifiers - codeplace = "<%s (macro)>" % filename - code = compile(source, codeplace, 'exec') - - # shield your eyes! - sm = sys.modules - tprm = "twisted.python.reflect.macros" - if not sm.has_key(tprm): - macros = types.ModuleType(tprm) - sm[tprm] = macros - macros.count = 0 - macros = sm[tprm] - macros.count += 1 - macroname = 'macro_' + str(macros.count) - tprmm = tprm + '.' + macroname - mymod = types.ModuleType(tprmm) - sys.modules[tprmm] = mymod - setattr(macros, macroname, mymod) - dict = mymod.__dict__ - - # Before we go on, I guess I should explain why I just did that. Basically - # it's a gross hack to get epydoc to work right, but the general idea is - # that it will be a useful aid in debugging in _any_ app which expects - # sys.modules to have the same globals as some function. For example, it - # would be useful if you were foolishly trying to pickle a wrapped function - # directly from a class that had been hooked. - - exec code in dict, dict - return dict[name] -macro = deprecated(Version("Twisted", 8, 2, 0))(macro) - - - def _determineClass(x): try: return x.__class__ @@ -576,11 +578,12 @@ -##the following were factored out of usage +## the following were factored out of usage @deprecated(Version("Twisted", 11, 0, 0), "inspect.getmro") def allYourBase(classObj, baseClass=None): - """allYourBase(classObj, baseClass=None) -> list of all base + """ + allYourBase(classObj, baseClass=None) -> list of all base classes that are subclasses of baseClass, unless it is None, in which case all bases will be added. """ @@ -602,7 +605,8 @@ def prefixedMethodNames(classObj, prefix): - """A list of method names with a given prefix in a given class. + """ + A list of method names with a given prefix in a given class. """ dct = {} addMethodNamesToDict(classObj, dct, prefix) @@ -633,7 +637,8 @@ def prefixedMethods(obj, prefix=''): - """A list of methods with a given prefix on a given instance. + """ + A list of methods with a given prefix on a given instance. """ dct = {} accumulateMethods(obj, dct, prefix) @@ -641,7 +646,8 @@ def accumulateMethods(obj, dict, prefix='', curClass=None): - """accumulateMethods(instance, dict, prefix) + """ + accumulateMethods(instance, dict, prefix) I recurse through the bases of instance.__class__, and add methods beginning with 'prefix' to 'dict', in the form of {'methodname':*instance*method_object}. @@ -660,7 +666,8 @@ def accumulateClassDict(classObj, attr, adict, baseClass=None): - """Accumulate all attributes of a given name in a class heirarchy into a single dictionary. + """ + Accumulate all attributes of a given name in a class hierarchy into a single dictionary. Assuming all class attributes of this name are dictionaries. If any of the dictionaries being accumulated have the same key, the @@ -669,23 +676,23 @@ Ex:: - | class Soy: - | properties = {\"taste\": \"bland\"} - | - | class Plant: - | properties = {\"colour\": \"green\"} - | - | class Seaweed(Plant): - | pass - | - | class Lunch(Soy, Seaweed): - | properties = {\"vegan\": 1 } - | - | dct = {} - | - | accumulateClassDict(Lunch, \"properties\", dct) - | - | print dct + class Soy: + properties = {\"taste\": \"bland\"} + + class Plant: + properties = {\"colour\": \"green\"} + + class Seaweed(Plant): + pass + + class Lunch(Soy, Seaweed): + properties = {\"vegan\": 1 } + + dct = {} + + accumulateClassDict(Lunch, \"properties\", dct) + + print dct {\"taste\": \"bland\", \"colour\": \"green\", \"vegan\": 1} """ @@ -696,7 +703,8 @@ def accumulateClassList(classObj, attr, listObj, baseClass=None): - """Accumulate all attributes of a given name in a class heirarchy into a single list. + """ + Accumulate all attributes of a given name in a class heirarchy into a single list. Assuming all class attributes of this name are lists. """ @@ -729,8 +737,9 @@ def objgrep(start, goal, eq=isLike, path='', paths=None, seen=None, showUnknowns=0, maxDepth=None): - '''An insanely CPU-intensive process for finding stuff. - ''' + """ + An insanely CPU-intensive process for finding stuff. + """ if paths is None: paths = [] if seen is None: @@ -810,7 +819,7 @@ 'QueueMethod', 'OriginalAccessor', 'funcinfo', 'fullFuncName', 'qual', 'getcurrent', 'getClass', 'isinst', - 'namedModule', 'namedObject', 'namedClass', 'namedAny', 'macro', + 'namedModule', 'namedObject', 'namedClass', 'namedAny', 'safe_repr', 'safe_str', 'allYourBase', 'accumulateBases', 'prefixedMethodNames', 'addMethodNamesToDict', 'prefixedMethods', 'accumulateClassDict', 'accumulateClassList', 'isSame', 'isLike', diff -Nru twisted-12.0.0/twisted/python/release.py twisted-12.2.0/twisted/python/release.py --- twisted-12.0.0/twisted/python/release.py 2008-07-29 20:13:54.000000000 +0000 +++ twisted-12.2.0/twisted/python/release.py 2012-02-08 19:50:23.000000000 +0000 @@ -1,3 +1,6 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + """ A release-automation toolkit. @@ -7,19 +10,22 @@ """ import os -import re # errors class DirectoryExists(OSError): - """Some directory exists when it shouldn't.""" + """ + Some directory exists when it shouldn't. + """ pass class DirectoryDoesntExist(OSError): - """Some directory doesn't exist when it should.""" + """ + Some directory doesn't exist when it should. + """ pass @@ -33,9 +39,9 @@ def sh(command, null=True, prompt=False): """ - I'll try to execute `command', and if `prompt' is true, I'll + I'll try to execute C{command}, and if C{prompt} is true, I'll ask before running it. If the command returns something other - than 0, I'll raise CommandFailed(command). + than 0, I'll raise C{CommandFailed(command)}. """ print "--$", command diff -Nru twisted-12.0.0/twisted/python/runtime.py twisted-12.2.0/twisted/python/runtime.py --- twisted-12.0.0/twisted/python/runtime.py 2011-05-05 02:48:02.000000000 +0000 +++ twisted-12.2.0/twisted/python/runtime.py 2012-05-27 09:22:59.000000000 +0000 @@ -10,12 +10,14 @@ import imp + def shortPythonVersion(): - hv = sys.hexversion - major = (hv & 0xff000000L) >> 24 - minor = (hv & 0x00ff0000L) >> 16 - teeny = (hv & 0x0000ff00L) >> 8 - return "%s.%s.%s" % (major,minor,teeny) + """ + Returns the Python version as a dot-separated string. + """ + return "%s.%s.%s" % sys.version_info[:3] + + knownPlatforms = { 'nt': 'win32', @@ -25,11 +27,15 @@ 'org.python.modules.os': 'java', } + + _timeFunctions = { #'win32': time.clock, 'win32': time.time, } + + class Platform: """Gives us information about the platform we're running on""" @@ -49,10 +55,12 @@ """Do we know about this platform?""" return self.type != None + def getType(self): """Return 'posix', 'win32' or 'java'""" return self.type + def isMacOSX(self): """Check if current platform is Mac OS X. @@ -61,13 +69,15 @@ """ return self._platform == "darwin" + def isWinNT(self): """Are we running in Windows NT?""" if self.getType() == 'win32': import _winreg try: - k=_winreg.OpenKeyEx(_winreg.HKEY_LOCAL_MACHINE, - r'Software\Microsoft\Windows NT\CurrentVersion') + k = _winreg.OpenKeyEx( + _winreg.HKEY_LOCAL_MACHINE, + r'Software\Microsoft\Windows NT\CurrentVersion') _winreg.QueryValueEx(k, 'SystemRoot') return 1 except WindowsError: @@ -75,6 +85,7 @@ # not windows NT return 0 + def isWindows(self): return self.getType() == 'win32' @@ -92,6 +103,16 @@ return False + def isLinux(self): + """ + Check if current platform is Linux. + + @return: C{True} if the current platform has been detected as Linux. + @rtype: C{bool} + """ + return self._platform.startswith("linux") + + def supportsThreads(self): """Can threads be created? """ diff -Nru twisted-12.0.0/twisted/python/sendmsg.c twisted-12.2.0/twisted/python/sendmsg.c --- twisted-12.0.0/twisted/python/sendmsg.c 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/python/sendmsg.c 2012-04-26 15:30:59.000000000 +0000 @@ -0,0 +1,502 @@ +/* + * Copyright (c) Twisted Matrix Laboratories. + * See LICENSE for details. + */ + +#define PY_SSIZE_T_CLEAN 1 +#include + +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +/* This may cause some warnings, but if you want to get rid of them, upgrade + * your Python version. */ +typedef int Py_ssize_t; +#endif + +#include +#include +#include + +/* + * As per + * : + * + * "To forestall portability problems, it is recommended that applications + * not use values larger than (2**31)-1 for the socklen_t type." + */ + +#define SOCKLEN_MAX 0x7FFFFFFF + +PyObject *sendmsg_socket_error; + +static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds); +static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds); +static PyObject *sendmsg_getsockfam(PyObject *self, PyObject *args, PyObject *keywds); + +static char sendmsg_doc[] = "\ +Bindings for sendmsg(2), recvmsg(2), and a minimal helper for inspecting\n\ +address family of a socket.\n\ +"; + +static char sendmsg_sendmsg_doc[] = "\ +Wrap the C sendmsg(2) function for sending \"messages\" on a socket.\n\ +\n\ +@param fd: The file descriptor of the socket over which to send a message.\n\ +@type fd: C{int}\n\ +\n\ +@param data: Bytes to write to the socket.\n\ +@type data: C{str}\n\ +\n\ +@param flags: Flags to affect how the message is sent. See the C{MSG_}\n\ + constants in the sendmsg(2) manual page. By default no flags are set.\n\ +@type flags: C{int}\n\ +\n\ +@param ancillary: Extra data to send over the socket outside of the normal\n\ + datagram or stream mechanism. By default no ancillary data is sent.\n\ +@type ancillary: C{list} of C{tuple} of C{int}, C{int}, and C{str}.\n\ +\n\ +@raise OverflowError: Raised if too much ancillary data is given.\n\ +@raise socket.error: Raised if the underlying syscall indicates an error.\n\ +\n\ +@return: The return value of the underlying syscall, if it succeeds.\n\ +"; + +static char sendmsg_recvmsg_doc[] = "\ +Wrap the C recvmsg(2) function for receiving \"messages\" on a socket.\n\ +\n\ +@param fd: The file descriptor of the socket over which to receve a message.\n\ +@type fd: C{int}\n\ +\n\ +@param flags: Flags to affect how the message is sent. See the C{MSG_}\n\ + constants in the sendmsg(2) manual page. By default no flags are set.\n\ +@type flags: C{int}\n\ +\n\ +@param maxsize: The maximum number of bytes to receive from the socket\n\ + using the datagram or stream mechanism. The default maximum is 8192.\n\ +@type maxsize: C{int}\n\ +\n\ +@param cmsg_size: The maximum number of bytes to receive from the socket\n\ + outside of the normal datagram or stream mechanism. The default maximum is 4096.\n\ +\n\ +@raise OverflowError: Raised if too much ancillary data is given.\n\ +@raise socket.error: Raised if the underlying syscall indicates an error.\n\ +\n\ +@return: A C{tuple} of three elements: the bytes received using the\n\ + datagram/stream mechanism, flags as an C{int} describing the data\n\ + received, and a C{list} of C{tuples} giving ancillary received data.\n\ +"; + +static char sendmsg_getsockfam_doc[] = "\ +Retrieve the address family of a given socket.\n\ +\n\ +@param fd: The file descriptor of the socket the address family of which\n\ + to retrieve.\n\ +@type fd: C{int}\n\ +\n\ +@raise socket.error: Raised if the underlying getsockname call indicates\n\ + an error.\n\ +\n\ +@return: A C{int} representing the address family of the socket. For\n\ + example, L{socket.AF_INET}, L{socket.AF_INET6}, or L{socket.AF_UNIX}.\n\ +"; + +static PyMethodDef sendmsg_methods[] = { + {"send1msg", (PyCFunction) sendmsg_sendmsg, METH_VARARGS | METH_KEYWORDS, + sendmsg_sendmsg_doc}, + {"recv1msg", (PyCFunction) sendmsg_recvmsg, METH_VARARGS | METH_KEYWORDS, + sendmsg_recvmsg_doc}, + {"getsockfam", (PyCFunction) sendmsg_getsockfam, + METH_VARARGS | METH_KEYWORDS, sendmsg_getsockfam_doc}, + {NULL, NULL, 0, NULL} +}; + + +PyMODINIT_FUNC initsendmsg(void) { + PyObject *module; + + sendmsg_socket_error = NULL; /* Make sure that this has a known value + before doing anything that might exit. */ + + module = Py_InitModule3("sendmsg", sendmsg_methods, sendmsg_doc); + + if (!module) { + return; + } + + /* + The following is the only value mentioned by POSIX: + http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html + */ + + if (-1 == PyModule_AddIntConstant(module, "SCM_RIGHTS", SCM_RIGHTS)) { + return; + } + + + /* BSD, Darwin, Hurd */ +#if defined(SCM_CREDS) + if (-1 == PyModule_AddIntConstant(module, "SCM_CREDS", SCM_CREDS)) { + return; + } +#endif + + /* Linux */ +#if defined(SCM_CREDENTIALS) + if (-1 == PyModule_AddIntConstant(module, "SCM_CREDENTIALS", SCM_CREDENTIALS)) { + return; + } +#endif + + /* Apparently everywhere, but not standardized. */ +#if defined(SCM_TIMESTAMP) + if (-1 == PyModule_AddIntConstant(module, "SCM_TIMESTAMP", SCM_TIMESTAMP)) { + return; + } +#endif + + module = PyImport_ImportModule("socket"); + if (!module) { + return; + } + + sendmsg_socket_error = PyObject_GetAttrString(module, "error"); + if (!sendmsg_socket_error) { + return; + } +} + +static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds) { + + int fd; + int flags = 0; + Py_ssize_t sendmsg_result; + struct msghdr message_header; + struct iovec iov[1]; + PyObject *ancillary = NULL; + PyObject *iterator = NULL; + PyObject *item = NULL; + PyObject *result_object = NULL; + + static char *kwlist[] = {"fd", "data", "flags", "ancillary", NULL}; + + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "it#|iO:sendmsg", kwlist, + &fd, + &iov[0].iov_base, + &iov[0].iov_len, + &flags, + &ancillary)) { + return NULL; + } + + message_header.msg_name = NULL; + message_header.msg_namelen = 0; + + message_header.msg_iov = iov; + message_header.msg_iovlen = 1; + + message_header.msg_control = NULL; + message_header.msg_controllen = 0; + + message_header.msg_flags = 0; + + if (ancillary) { + + if (!PyList_Check(ancillary)) { + PyErr_Format(PyExc_TypeError, + "send1msg argument 3 expected list, got %s", + ancillary->ob_type->tp_name); + goto finished; + } + + iterator = PyObject_GetIter(ancillary); + + if (iterator == NULL) { + goto finished; + } + + size_t all_data_len = 0; + + /* First we need to know how big the buffer needs to be in order to + have enough space for all of the messages. */ + while ( (item = PyIter_Next(iterator)) ) { + int type, level; + Py_ssize_t data_len; + size_t prev_all_data_len; + char *data; + + if (!PyTuple_Check(item)) { + PyErr_Format(PyExc_TypeError, + "send1msg argument 3 expected list of tuple, " + "got list containing %s", + item->ob_type->tp_name); + goto finished; + } + + if (!PyArg_ParseTuple( + item, "iit#:sendmsg ancillary data (level, type, data)", + &level, &type, &data, &data_len)) { + goto finished; + } + + prev_all_data_len = all_data_len; + all_data_len += CMSG_SPACE(data_len); + + Py_DECREF(item); + item = NULL; + + if (all_data_len < prev_all_data_len) { + PyErr_Format(PyExc_OverflowError, + "Too much msg_control to fit in a size_t: %zu", + prev_all_data_len); + goto finished; + } + } + + Py_DECREF(iterator); + iterator = NULL; + + /* Allocate the buffer for all of the ancillary elements, if we have + * any. */ + if (all_data_len) { + if (all_data_len > SOCKLEN_MAX) { + PyErr_Format(PyExc_OverflowError, + "Too much msg_control to fit in a socklen_t: %zu", + all_data_len); + goto finished; + } + message_header.msg_control = PyMem_Malloc(all_data_len); + if (!message_header.msg_control) { + PyErr_NoMemory(); + goto finished; + } + } else { + message_header.msg_control = NULL; + } + message_header.msg_controllen = (socklen_t) all_data_len; + + iterator = PyObject_GetIter(ancillary); /* again */ + + if (!iterator) { + goto finished; + } + + /* Unpack the tuples into the control message. */ + struct cmsghdr *control_message = CMSG_FIRSTHDR(&message_header); + while ( (item = PyIter_Next(iterator)) ) { + int data_len, type, level; + size_t data_size; + unsigned char *data, *cmsg_data; + + /* We explicitly allocated enough space for all ancillary data + above; if there isn't enough room, all bets are off. */ + assert(control_message); + + if (!PyArg_ParseTuple(item, + "iit#:sendmsg ancillary data (level, type, data)", + &level, + &type, + &data, + &data_len)) { + goto finished; + } + + control_message->cmsg_level = level; + control_message->cmsg_type = type; + data_size = CMSG_LEN(data_len); + + if (data_size > SOCKLEN_MAX) { + PyErr_Format(PyExc_OverflowError, + "CMSG_LEN(%d) > SOCKLEN_MAX", data_len); + goto finished; + } + + control_message->cmsg_len = (socklen_t) data_size; + + cmsg_data = CMSG_DATA(control_message); + memcpy(cmsg_data, data, data_len); + + Py_DECREF(item); + item = NULL; + + control_message = CMSG_NXTHDR(&message_header, control_message); + } + Py_DECREF(iterator); + iterator = NULL; + + if (PyErr_Occurred()) { + goto finished; + } + } + + sendmsg_result = sendmsg(fd, &message_header, flags); + + if (sendmsg_result < 0) { + PyErr_SetFromErrno(sendmsg_socket_error); + goto finished; + } + + result_object = Py_BuildValue("n", sendmsg_result); + + finished: + + if (item) { + Py_DECREF(item); + item = NULL; + } + if (iterator) { + Py_DECREF(iterator); + iterator = NULL; + } + if (message_header.msg_control) { + PyMem_Free(message_header.msg_control); + message_header.msg_control = NULL; + } + return result_object; +} + +static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds) { + int fd = -1; + int flags = 0; + int maxsize = 8192; + int cmsg_size = 4096; + size_t cmsg_space; + size_t cmsg_overhead; + Py_ssize_t recvmsg_result; + + struct msghdr message_header; + struct cmsghdr *control_message; + struct iovec iov[1]; + char *cmsgbuf; + PyObject *ancillary; + PyObject *final_result = NULL; + + static char *kwlist[] = {"fd", "flags", "maxsize", "cmsg_size", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii:recvmsg", kwlist, + &fd, &flags, &maxsize, &cmsg_size)) { + return NULL; + } + + cmsg_space = CMSG_SPACE(cmsg_size); + + /* overflow check */ + if (cmsg_space > SOCKLEN_MAX) { + PyErr_Format(PyExc_OverflowError, + "CMSG_SPACE(cmsg_size) greater than SOCKLEN_MAX: %d", + cmsg_size); + return NULL; + } + + message_header.msg_name = NULL; + message_header.msg_namelen = 0; + + iov[0].iov_len = maxsize; + iov[0].iov_base = PyMem_Malloc(maxsize); + + if (!iov[0].iov_base) { + PyErr_NoMemory(); + return NULL; + } + + message_header.msg_iov = iov; + message_header.msg_iovlen = 1; + + cmsgbuf = PyMem_Malloc(cmsg_space); + + if (!cmsgbuf) { + PyMem_Free(iov[0].iov_base); + PyErr_NoMemory(); + return NULL; + } + + memset(cmsgbuf, 0, cmsg_space); + message_header.msg_control = cmsgbuf; + /* see above for overflow check */ + message_header.msg_controllen = (socklen_t) cmsg_space; + + recvmsg_result = recvmsg(fd, &message_header, flags); + if (recvmsg_result < 0) { + PyErr_SetFromErrno(sendmsg_socket_error); + goto finished; + } + + ancillary = PyList_New(0); + if (!ancillary) { + goto finished; + } + + for (control_message = CMSG_FIRSTHDR(&message_header); + control_message; + control_message = CMSG_NXTHDR(&message_header, + control_message)) { + PyObject *entry; + + /* Some platforms apparently always fill out the ancillary data + structure with a single bogus value if none is provided; ignore it, + if that is the case. */ + + if ((!(control_message->cmsg_level)) && + (!(control_message->cmsg_type))) { + continue; + } + + /* + * Figure out how much of the cmsg size is cmsg structure overhead - in + * other words, how much is not part of the application data. This lets + * us compute the right application data size below. There should + * really be a CMSG_ macro for this. + */ + cmsg_overhead = (char*)CMSG_DATA(control_message) - (char*)control_message; + + entry = Py_BuildValue( + "(iis#)", + control_message->cmsg_level, + control_message->cmsg_type, + CMSG_DATA(control_message), + (Py_ssize_t) (control_message->cmsg_len - cmsg_overhead)); + + if (!entry) { + Py_DECREF(ancillary); + goto finished; + } + + if (PyList_Append(ancillary, entry) < 0) { + Py_DECREF(ancillary); + Py_DECREF(entry); + goto finished; + } else { + Py_DECREF(entry); + } + } + + final_result = Py_BuildValue( + "s#iO", + iov[0].iov_base, + recvmsg_result, + message_header.msg_flags, + ancillary); + + Py_DECREF(ancillary); + + finished: + PyMem_Free(iov[0].iov_base); + PyMem_Free(cmsgbuf); + return final_result; +} + +static PyObject *sendmsg_getsockfam(PyObject *self, PyObject *args, + PyObject *keywds) { + int fd; + struct sockaddr sa; + static char *kwlist[] = {"fd", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", kwlist, &fd)) { + return NULL; + } + socklen_t sz = sizeof(sa); + if (getsockname(fd, &sa, &sz)) { + PyErr_SetFromErrno(sendmsg_socket_error); + return NULL; + } + return Py_BuildValue("i", sa.sa_family); +} diff -Nru twisted-12.0.0/twisted/python/systemd.py twisted-12.2.0/twisted/python/systemd.py --- twisted-12.0.0/twisted/python/systemd.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/python/systemd.py 2012-04-04 21:03:05.000000000 +0000 @@ -0,0 +1,87 @@ +# -*- test-case-name: twisted.python.test.test_systemd -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Integration with systemd. + +Currently only the minimum APIs necessary for using systemd's socket activation +feature are supported. +""" + +__all__ = ['ListenFDs'] + +from os import getpid + + +class ListenFDs(object): + """ + L{ListenFDs} provides access to file descriptors inherited from systemd. + + Typically L{ListenFDs.fromEnvironment} should be used to construct a new + instance of L{ListenFDs}. + + @cvar _START: File descriptors inherited from systemd are always + consecutively numbered, with a fixed lowest "starting" descriptor. This + gives the default starting descriptor. Since this must agree with the + value systemd is using, it typically should not be overridden. + @type _START: C{int} + + @ivar _descriptors: A C{list} of C{int} giving the descriptors which were + inherited. + """ + _START = 3 + + def __init__(self, descriptors): + """ + @param descriptors: The descriptors which will be returned from calls to + C{inheritedDescriptors}. + """ + self._descriptors = descriptors + + + @classmethod + def fromEnvironment(cls, environ=None, start=None): + """ + @param environ: A dictionary-like object to inspect to discover + inherited descriptors. By default, C{None}, indicating that the + real process environment should be inspected. The default is + suitable for typical usage. + + @param start: An integer giving the lowest value of an inherited + descriptor systemd will give us. By default, C{None}, indicating + the known correct (that is, in agreement with systemd) value will be + used. The default is suitable for typical usage. + + @return: A new instance of C{cls} which can be used to look up the + descriptors which have been inherited. + """ + if environ is None: + from os import environ + if start is None: + start = cls._START + + descriptors = [] + + try: + pid = int(environ['LISTEN_PID']) + except (KeyError, ValueError): + pass + else: + if pid == getpid(): + try: + count = int(environ['LISTEN_FDS']) + except (KeyError, ValueError): + pass + else: + descriptors = range(start, start + count) + del environ['LISTEN_PID'], environ['LISTEN_FDS'] + + return cls(descriptors) + + + def inheritedDescriptors(self): + """ + @return: The configured list of descriptors. + """ + return list(self._descriptors) diff -Nru twisted-12.0.0/twisted/python/test/pullpipe.py twisted-12.2.0/twisted/python/test/pullpipe.py --- twisted-12.0.0/twisted/python/test/pullpipe.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/pullpipe.py 2012-04-14 10:02:04.000000000 +0000 @@ -0,0 +1,40 @@ +#!/usr/bin/python +# -*- test-case-name: twisted.python.test.test_sendmsg -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +import sys, os +from struct import unpack + +# This makes me sad. Why aren't things nice? +sys.path.insert(0, __file__.rsplit('/', 4)[0]) + +from twisted.python.sendmsg import recv1msg + +def recvfd(socketfd): + """ + Receive a file descriptor from a L{send1msg} message on the given C{AF_UNIX} + socket. + + @param socketfd: An C{AF_UNIX} socket, attached to another process waiting + to send sockets via the ancillary data mechanism in L{send1msg}. + + @param fd: C{int} + + @return: a 2-tuple of (new file descriptor, description). + + @rtype: 2-tuple of (C{int}, C{str}) + """ + data, flags, ancillary = recv1msg(socketfd) + [(cmsg_level, cmsg_type, packedFD)] = ancillary + # cmsg_level and cmsg_type really need to be SOL_SOCKET / SCM_RIGHTS, but + # since those are the *only* standard values, there's not much point in + # checking. + [unpackedFD] = unpack("i", packedFD) + return (unpackedFD, data) + + +if __name__ == '__main__': + fd, description = recvfd(int(sys.argv[1])) + os.write(fd, "Test fixture data: %s.\n" % (description,)) + os.close(fd) diff -Nru twisted-12.0.0/twisted/python/test/test_constants.py twisted-12.2.0/twisted/python/test/test_constants.py --- twisted-12.0.0/twisted/python/test/test_constants.py 2011-12-10 21:39:18.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_constants.py 2012-03-11 09:04:58.000000000 +0000 @@ -7,7 +7,8 @@ from twisted.trial.unittest import TestCase -from twisted.python.constants import NamedConstant, Names, ValueConstant, Values +from twisted.python.constants import ( + NamedConstant, Names, ValueConstant, Values, FlagConstant, Flags) class NamedConstantTests(TestCase): @@ -405,3 +406,373 @@ self.STATUS.OK # Side-effects! second = self.STATUS._enumerants self.assertIdentical(first, second) + + +class _FlagsTestsMixin(object): + """ + Mixin defining setup code for any tests for L{Flags} subclasses. + + @ivar FXF: A L{Flags} subclass created for each test method. + """ + def setUp(self): + """ + Create a fresh new L{Flags} subclass for each unit test to use. Since + L{Flags} is stateful, re-using the same subclass across test methods + makes exercising all of the implementation code paths difficult. + """ + class FXF(Flags): + # Implicitly assign three flag values based on definition order + READ = FlagConstant() + WRITE = FlagConstant() + APPEND = FlagConstant() + + # Explicitly assign one flag value by passing it in + EXCLUSIVE = FlagConstant(0x20) + + # Implicitly assign another flag value, following the previously + # specified explicit value. + TEXT = FlagConstant() + + self.FXF = FXF + + + +class FlagsTests(_FlagsTestsMixin, TestCase, _ConstantsTestsMixin): + """ + Tests for L{twisted.python.constants.Flags}, a base class for containers of + related, combinable flag or bitvector-like constants. + """ + def test_notInstantiable(self): + """ + A subclass of L{Flags} raises L{TypeError} if an attempt is made to + instantiate it. + """ + self._notInstantiableTest("FXF", self.FXF) + + + def test_symbolicAttributes(self): + """ + Each name associated with a L{FlagConstant} instance in the definition + of a L{Flags} subclass is available as an attribute on the resulting + class. + """ + self.assertTrue(hasattr(self.FXF, "READ")) + self.assertTrue(hasattr(self.FXF, "WRITE")) + self.assertTrue(hasattr(self.FXF, "APPEND")) + self.assertTrue(hasattr(self.FXF, "EXCLUSIVE")) + self.assertTrue(hasattr(self.FXF, "TEXT")) + + + def test_withoutOtherAttributes(self): + """ + As usual, names not defined in the class scope of a L{Flags} subclass + are not available as attributes on the resulting class. + """ + self.assertFalse(hasattr(self.FXF, "foo")) + + + def test_representation(self): + """ + The string representation of a constant on a L{Flags} subclass includes + the name of the L{Flags} subclass and the name of the constant itself. + """ + self.assertEqual("", repr(self.FXF.READ)) + + + def test_lookupByName(self): + """ + Constants can be looked up by name using L{Flags.lookupByName}. + """ + flag = self.FXF.lookupByName("READ") + self.assertIdentical(self.FXF.READ, flag) + + + def test_notLookupMissingByName(self): + """ + Names not defined with a L{FlagConstant} instance cannot be looked up + using L{Flags.lookupByName}. + """ + self.assertRaises(ValueError, self.FXF.lookupByName, "lookupByName") + self.assertRaises(ValueError, self.FXF.lookupByName, "__init__") + self.assertRaises(ValueError, self.FXF.lookupByName, "foo") + + + def test_lookupByValue(self): + """ + Constants can be looked up by their associated value, defined implicitly + by the position in which the constant appears in the class definition or + explicitly by the argument passed to L{FlagConstant}. + """ + flag = self.FXF.lookupByValue(0x01) + self.assertIdentical(flag, self.FXF.READ) + + flag = self.FXF.lookupByValue(0x02) + self.assertIdentical(flag, self.FXF.WRITE) + + flag = self.FXF.lookupByValue(0x04) + self.assertIdentical(flag, self.FXF.APPEND) + + flag = self.FXF.lookupByValue(0x20) + self.assertIdentical(flag, self.FXF.EXCLUSIVE) + + flag = self.FXF.lookupByValue(0x40) + self.assertIdentical(flag, self.FXF.TEXT) + + + def test_lookupDuplicateByValue(self): + """ + If more than one constant is associated with a particular value, + L{Flags.lookupByValue} returns whichever of them is defined first. + """ + class TIMEX(Flags): + # (timex.mode) + ADJ_OFFSET = FlagConstant(0x0001) # time offset + + # xntp 3.4 compatibility names + MOD_OFFSET = FlagConstant(0x0001) + + self.assertIdentical(TIMEX.lookupByValue(0x0001), TIMEX.ADJ_OFFSET) + + + def test_notLookupMissingByValue(self): + """ + L{Flags.lookupByValue} raises L{ValueError} when called with a value + with which no constant is associated. + """ + self.assertRaises(ValueError, self.FXF.lookupByValue, 0x10) + + + def test_name(self): + """ + The C{name} attribute of one of the constants gives that constant's + name. + """ + self.assertEqual("READ", self.FXF.READ.name) + + + def test_attributeIdentity(self): + """ + Repeated access of an attribute associated with a L{FlagConstant} value + in a L{Flags} subclass results in the same object. + """ + self.assertIdentical(self.FXF.READ, self.FXF.READ) + + + def test_iterconstants(self): + """ + L{Flags.iterconstants} returns an iterator over all of the constants + defined in the class, in the order they were defined. + """ + constants = list(self.FXF.iterconstants()) + self.assertEqual( + [self.FXF.READ, self.FXF.WRITE, self.FXF.APPEND, + self.FXF.EXCLUSIVE, self.FXF.TEXT], + constants) + + + def test_attributeIterconstantsIdentity(self): + """ + The constants returned from L{Flags.iterconstants} are identical to the + constants accessible using attributes. + """ + constants = list(self.FXF.iterconstants()) + self.assertIdentical(self.FXF.READ, constants[0]) + self.assertIdentical(self.FXF.WRITE, constants[1]) + self.assertIdentical(self.FXF.APPEND, constants[2]) + self.assertIdentical(self.FXF.EXCLUSIVE, constants[3]) + self.assertIdentical(self.FXF.TEXT, constants[4]) + + + def test_iterconstantsIdentity(self): + """ + The constants returned from L{Flags.iterconstants} are identical on each + call to that method. + """ + constants = list(self.FXF.iterconstants()) + again = list(self.FXF.iterconstants()) + self.assertIdentical(again[0], constants[0]) + self.assertIdentical(again[1], constants[1]) + self.assertIdentical(again[2], constants[2]) + self.assertIdentical(again[3], constants[3]) + self.assertIdentical(again[4], constants[4]) + + + def test_initializedOnce(self): + """ + L{Flags._enumerants} is initialized once and its value re-used on + subsequent access. + """ + first = self.FXF._enumerants + self.FXF.READ # Side-effects! + second = self.FXF._enumerants + self.assertIdentical(first, second) + + + +class FlagConstantSimpleOrTests(_FlagsTestsMixin, TestCase): + """ + Tests for the C{|} operator as defined for L{FlagConstant} instances, used + to create new L{FlagConstant} instances representing both of two existing + L{FlagConstant} instances from the same L{Flags} class. + """ + def test_value(self): + """ + The value of the L{FlagConstant} which results from C{|} has all of the + bits set which were set in either of the values of the two original + constants. + """ + flag = self.FXF.READ | self.FXF.WRITE + self.assertEqual(self.FXF.READ.value | self.FXF.WRITE.value, flag.value) + + + def test_name(self): + """ + The name of the L{FlagConstant} instance which results from C{|} + includes the names of both of the two original constants. + """ + flag = self.FXF.READ | self.FXF.WRITE + self.assertEqual("{READ,WRITE}", flag.name) + + + def test_representation(self): + """ + The string representation of a L{FlagConstant} instance which results + from C{|} includes the names of both of the two original constants. + """ + flag = self.FXF.READ | self.FXF.WRITE + self.assertEqual("", repr(flag)) + + + +class FlagConstantSimpleAndTests(_FlagsTestsMixin, TestCase): + """ + Tests for the C{&} operator as defined for L{FlagConstant} instances, used + to create new L{FlagConstant} instances representing the common parts of two + existing L{FlagConstant} instances from the same L{Flags} class. + """ + def test_value(self): + """ + The value of the L{FlagConstant} which results from C{&} has all of the + bits set which were set in both of the values of the two original + constants. + """ + readWrite = (self.FXF.READ | self.FXF.WRITE) + writeAppend = (self.FXF.WRITE | self.FXF.APPEND) + flag = readWrite & writeAppend + self.assertEqual(self.FXF.WRITE.value, flag.value) + + + def test_name(self): + """ + The name of the L{FlagConstant} instance which results from C{&} + includes the names of only the flags which were set in both of the two + original constants. + """ + readWrite = (self.FXF.READ | self.FXF.WRITE) + writeAppend = (self.FXF.WRITE | self.FXF.APPEND) + flag = readWrite & writeAppend + self.assertEqual("WRITE", flag.name) + + + def test_representation(self): + """ + The string representation of a L{FlagConstant} instance which results + from C{&} includes the names of only the flags which were set in both + both of the two original constants. + """ + readWrite = (self.FXF.READ | self.FXF.WRITE) + writeAppend = (self.FXF.WRITE | self.FXF.APPEND) + flag = readWrite & writeAppend + self.assertEqual("", repr(flag)) + + + +class FlagConstantSimpleExclusiveOrTests(_FlagsTestsMixin, TestCase): + """ + Tests for the C{^} operator as defined for L{FlagConstant} instances, used + to create new L{FlagConstant} instances representing the uncommon parts of + two existing L{FlagConstant} instances from the same L{Flags} class. + """ + def test_value(self): + """ + The value of the L{FlagConstant} which results from C{^} has all of the + bits set which were set in exactly one of the values of the two original + constants. + """ + readWrite = (self.FXF.READ | self.FXF.WRITE) + writeAppend = (self.FXF.WRITE | self.FXF.APPEND) + flag = readWrite ^ writeAppend + self.assertEqual(self.FXF.READ.value | self.FXF.APPEND.value, flag.value) + + + def test_name(self): + """ + The name of the L{FlagConstant} instance which results from C{^} + includes the names of only the flags which were set in exactly one of + the two original constants. + """ + readWrite = (self.FXF.READ | self.FXF.WRITE) + writeAppend = (self.FXF.WRITE | self.FXF.APPEND) + flag = readWrite ^ writeAppend + self.assertEqual("{APPEND,READ}", flag.name) + + + def test_representation(self): + """ + The string representation of a L{FlagConstant} instance which results + from C{^} includes the names of only the flags which were set in exactly + one of the two original constants. + """ + readWrite = (self.FXF.READ | self.FXF.WRITE) + writeAppend = (self.FXF.WRITE | self.FXF.APPEND) + flag = readWrite ^ writeAppend + self.assertEqual("", repr(flag)) + + + +class FlagConstantNegationTests(_FlagsTestsMixin, TestCase): + """ + Tests for the C{~} operator as defined for L{FlagConstant} instances, used + to create new L{FlagConstant} instances representing all the flags from a + L{Flags} class not set in a particular L{FlagConstant} instance. + """ + def test_value(self): + """ + The value of the L{FlagConstant} which results from C{~} has all of the + bits set which were not set in the original constant. + """ + flag = ~self.FXF.READ + self.assertEqual( + self.FXF.WRITE.value | + self.FXF.APPEND.value | + self.FXF.EXCLUSIVE.value | + self.FXF.TEXT.value, + flag.value) + + flag = ~self.FXF.WRITE + self.assertEqual( + self.FXF.READ.value | + self.FXF.APPEND.value | + self.FXF.EXCLUSIVE.value | + self.FXF.TEXT.value, + flag.value) + + + def test_name(self): + """ + The name of the L{FlagConstant} instance which results from C{~} + includes the names of all the flags which were not set in the original + constant. + """ + flag = ~self.FXF.WRITE + self.assertEqual("{APPEND,EXCLUSIVE,READ,TEXT}", flag.name) + + + def test_representation(self): + """ + The string representation of a L{FlagConstant} instance which results + from C{~} includes the names of all the flags which were not set in the + original constant. + """ + flag = ~self.FXF.WRITE + self.assertEqual("", repr(flag)) diff -Nru twisted-12.0.0/twisted/python/test/test_dist.py twisted-12.2.0/twisted/python/test/test_dist.py --- twisted-12.0.0/twisted/python/test/test_dist.py 2011-09-26 16:28:23.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_dist.py 2012-07-25 19:04:04.000000000 +0000 @@ -7,16 +7,19 @@ import os +import sys from distutils.core import Distribution from twisted.trial.unittest import TestCase from twisted.python import dist -from twisted.python.dist import get_setup_args, ConditionalExtension +from twisted.python.dist import (get_setup_args, ConditionalExtension, + build_scripts_twisted) from twisted.python.filepath import FilePath + class SetupTest(TestCase): """ Tests for L{get_setup_args}. @@ -56,6 +59,107 @@ +class GetExtensionsTest(TestCase): + """ + Tests for L{dist.getExtensions}. + """ + + setupTemplate = ( + "from twisted.python.dist import ConditionalExtension\n" + "extensions = [\n" + " ConditionalExtension(\n" + " '%s', ['twisted/some/thing.c'],\n" + " condition=lambda builder: True)\n" + " ]\n") + + def setUp(self): + self.basedir = FilePath(self.mktemp()).child("twisted") + self.basedir.makedirs() + self.addCleanup(os.chdir, os.getcwd()) + os.chdir(self.basedir.parent().path) + + + def writeSetup(self, name, *path): + """ + Write out a C{setup.py} file to a location determined by + L{self.basedir} and L{path}. L{self.setupTemplate} is used to + generate its contents. + """ + outdir = self.basedir.descendant(path) + outdir.makedirs() + setup = outdir.child("setup.py") + setup.setContent(self.setupTemplate % (name,)) + + + def writeEmptySetup(self, *path): + """ + Write out an empty C{setup.py} file to a location determined by + L{self.basedir} and L{path}. + """ + outdir = self.basedir.descendant(path) + outdir.makedirs() + outdir.child("setup.py").setContent("") + + + def assertExtensions(self, expected): + """ + Assert that the given names match the (sorted) names of discovered + extensions. + """ + extensions = dist.getExtensions() + names = [extension.name for extension in extensions] + self.assertEqual(sorted(names), expected) + + + def test_getExtensions(self): + """ + Files named I{setup.py} in I{twisted/topfiles} and I{twisted/*/topfiles} + are executed with L{execfile} in order to discover the extensions they + declare. + """ + self.writeSetup("twisted.transmutate", "topfiles") + self.writeSetup("twisted.tele.port", "tele", "topfiles") + self.assertExtensions(["twisted.tele.port", "twisted.transmutate"]) + + + def test_getExtensionsTooDeep(self): + """ + Files named I{setup.py} in I{topfiles} directories are not considered if + they are too deep in the directory hierarchy. + """ + self.writeSetup("twisted.trans.mog.rify", "trans", "mog", "topfiles") + self.assertExtensions([]) + + + def test_getExtensionsNotTopfiles(self): + """ + The folder in which I{setup.py} is discovered must be called I{topfiles} + otherwise it is ignored. + """ + self.writeSetup("twisted.metamorphosis", "notfiles") + self.assertExtensions([]) + + + def test_getExtensionsNotSupportedOnJava(self): + """ + Extensions are not supported on Java-based platforms. + """ + self.addCleanup(setattr, sys, "platform", sys.platform) + sys.platform = "java" + self.writeSetup("twisted.sorcery", "topfiles") + self.assertExtensions([]) + + + def test_getExtensionsExtensionsLocalIsOptional(self): + """ + It is acceptable for extensions to not define the C{extensions} local + variable. + """ + self.writeEmptySetup("twisted.necromancy", "topfiles") + self.assertExtensions([]) + + + class GetVersionTest(TestCase): """ Tests for L{dist.getVersion}. @@ -93,6 +197,7 @@ self.assertEqual(dist.getVersion("blat", base=self.dirname), "9.8.10") + class GetScriptsTest(TestCase): """ Tests for L{dist.getScripts} which returns the scripts which should be @@ -193,6 +298,110 @@ +class DummyCommand: + """ + A fake Command. + """ + def __init__(self, **kwargs): + for kw, val in kwargs.items(): + setattr(self, kw, val) + + def ensure_finalized(self): + pass + + + +class BuildScriptsTest(TestCase): + """ + Tests for L{dist.build_scripts_twisted}. + """ + + def setUp(self): + self.source = FilePath(self.mktemp()) + self.target = FilePath(self.mktemp()) + self.source.makedirs() + self.addCleanup(os.chdir, os.getcwd()) + os.chdir(self.source.path) + + + def buildScripts(self): + """ + Write 3 types of scripts and run the L{build_scripts_twisted} + command. + """ + self.writeScript(self.source, "script1", + ("#! /usr/bin/env python2.7\n" + "# bogus script w/ Python sh-bang\n" + "pass\n")) + + self.writeScript(self.source, "script2.py", + ("#!/usr/bin/python\n" + "# bogus script w/ Python sh-bang\n" + "pass\n")) + + self.writeScript(self.source, "shell.sh", + ("#!/bin/sh\n" + "# bogus shell script w/ sh-bang\n" + "exit 0\n")) + + expected = ['script1', 'script2.py', 'shell.sh'] + cmd = self.getBuildScriptsCmd(self.target, + [self.source.child(fn).path + for fn in expected]) + cmd.finalize_options() + cmd.run() + + return self.target.listdir() + + + def getBuildScriptsCmd(self, target, scripts): + """ + Create a distutils L{Distribution} with a L{DummyCommand} and wrap it + in L{build_scripts_twisted}. + + @type target: L{FilePath} + """ + dist = Distribution() + dist.scripts = scripts + dist.command_obj["build"] = DummyCommand( + build_scripts = target.path, + force = 1, + executable = sys.executable + ) + return build_scripts_twisted(dist) + + + def writeScript(self, dir, name, text): + """ + Write the script to disk. + """ + with open(dir.child(name).path, "w") as f: + f.write(text) + + + def test_notWindows(self): + """ + L{build_scripts_twisted} does not rename scripts on non-Windows + platforms. + """ + self.patch(os, "name", "twisted") + built = self.buildScripts() + for name in ['script1', 'script2.py', 'shell.sh']: + self.assertTrue(name in built) + + + def test_windows(self): + """ + L{build_scripts_twisted} renames scripts so they end with '.py' on + the Windows platform. + """ + self.patch(os, "name", "nt") + built = self.buildScripts() + for name in ['script1.py', 'script2.py', 'shell.sh.py']: + self.assertTrue(name in built) + + + class FakeModule(object): """ A fake module, suitable for dependency injection in testing. @@ -206,6 +415,7 @@ """ self._attrs = attrs + def __getattr__(self, name): """ Gets an attribute of this fake module from its attrs. diff -Nru twisted-12.0.0/twisted/python/test/test_fakepwd.py twisted-12.2.0/twisted/python/test/test_fakepwd.py --- twisted-12.0.0/twisted/python/test/test_fakepwd.py 2011-11-25 01:19:18.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_fakepwd.py 2012-08-01 09:15:27.000000000 +0000 @@ -99,7 +99,7 @@ username, password, uid, gid, gecos, dir, shell = self.getExistingUserInfo() for entry in [db.getpwuid(uid), db.getpwnam(username), db.getpwall()[0]]: self.assertIsInstance(len(entry), int) - self.assertEquals(len(entry), 7) + self.assertEqual(len(entry), 7) def test_recordIndexable(self): @@ -208,7 +208,7 @@ found with C{getpwuid} and only cause trouble). """ while True: - entry = self._users.next() + entry = next(self._users) uid = entry.pw_uid if uid not in self._uids: self._uids.add(uid) @@ -235,15 +235,15 @@ flag) = self.getExistingUserInfo() entry = self.database.getspnam(username) - self.assertEquals(entry.sp_nam, username) - self.assertEquals(entry.sp_pwd, password) - self.assertEquals(entry.sp_lstchg, lastChange) - self.assertEquals(entry.sp_min, min) - self.assertEquals(entry.sp_max, max) - self.assertEquals(entry.sp_warn, warn) - self.assertEquals(entry.sp_inact, inact) - self.assertEquals(entry.sp_expire, expire) - self.assertEquals(entry.sp_flag, flag) + self.assertEqual(entry.sp_nam, username) + self.assertEqual(entry.sp_pwd, password) + self.assertEqual(entry.sp_lstchg, lastChange) + self.assertEqual(entry.sp_min, min) + self.assertEqual(entry.sp_max, max) + self.assertEqual(entry.sp_warn, warn) + self.assertEqual(entry.sp_inact, inact) + self.assertEqual(entry.sp_expire, expire) + self.assertEqual(entry.sp_flag, flag) def test_noSuchName(self): @@ -263,7 +263,7 @@ username = self.getExistingUserInfo()[0] for entry in [db.getspnam(username), db.getspall()[0]]: self.assertIsInstance(len(entry), int) - self.assertEquals(len(entry), 9) + self.assertEqual(len(entry), 9) def test_recordIndexable(self): @@ -278,17 +278,17 @@ (username, password, lastChange, min, max, warn, inact, expire, flag) = self.getExistingUserInfo() for entry in [db.getspnam(username), db.getspall()[0]]: - self.assertEquals(entry[0], username) - self.assertEquals(entry[1], password) - self.assertEquals(entry[2], lastChange) - self.assertEquals(entry[3], min) - self.assertEquals(entry[4], max) - self.assertEquals(entry[5], warn) - self.assertEquals(entry[6], inact) - self.assertEquals(entry[7], expire) - self.assertEquals(entry[8], flag) + self.assertEqual(entry[0], username) + self.assertEqual(entry[1], password) + self.assertEqual(entry[2], lastChange) + self.assertEqual(entry[3], min) + self.assertEqual(entry[4], max) + self.assertEqual(entry[5], warn) + self.assertEqual(entry[6], inact) + self.assertEqual(entry[7], expire) + self.assertEqual(entry[8], flag) - self.assertEquals(len(entry), len(list(entry))) + self.assertEqual(len(entry), len(list(entry))) self.assertRaises(IndexError, getitem, entry, 9) @@ -349,15 +349,15 @@ expire, flag) for [entry] in [[db.getspnam(username)], db.getspall()]: - self.assertEquals(entry.sp_nam, username) - self.assertEquals(entry.sp_pwd, password) - self.assertEquals(entry.sp_lstchg, lastChange) - self.assertEquals(entry.sp_min, min) - self.assertEquals(entry.sp_max, max) - self.assertEquals(entry.sp_warn, warn) - self.assertEquals(entry.sp_inact, inact) - self.assertEquals(entry.sp_expire, expire) - self.assertEquals(entry.sp_flag, flag) + self.assertEqual(entry.sp_nam, username) + self.assertEqual(entry.sp_pwd, password) + self.assertEqual(entry.sp_lstchg, lastChange) + self.assertEqual(entry.sp_min, min) + self.assertEqual(entry.sp_max, max) + self.assertEqual(entry.sp_warn, warn) + self.assertEqual(entry.sp_inact, inact) + self.assertEqual(entry.sp_expire, expire) + self.assertEqual(entry.sp_flag, flag) @@ -382,5 +382,5 @@ """ Read and return the next record from C{self._users}. """ - return self._users.next() + return next(self._users) diff -Nru twisted-12.0.0/twisted/python/test/test_release.py twisted-12.2.0/twisted/python/test/test_release.py --- twisted-12.0.0/twisted/python/test/test_release.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_release.py 2012-08-12 16:48:05.000000000 +0000 @@ -20,7 +20,7 @@ from twisted.trial.unittest import TestCase -from twisted.python.compat import set +from twisted.python.compat import execfile, set from twisted.python.procutils import which from twisted.python import release from twisted.python.filepath import FilePath @@ -476,7 +476,7 @@ def chAndBreak(): os.mkdir('releaseCh') os.chdir('releaseCh') - 1/0 + 1//0 self.assertRaises(ZeroDivisionError, release.runChdirSafe, chAndBreak) self.assertEqual(cwd, os.getcwd()) @@ -2055,6 +2055,40 @@ self.assertExtractedStructure(outputFile, outStructure) + def test_excluded(self): + """ + bin/admin and doc/historic are excluded from the Twisted tarball. + """ + structure = { + "bin": {"admin": {"blah": "ADMIN"}, + "twistd": "TWISTD"}, + "twisted": + {"web": + {"__init__.py": "import WEB", + "topfiles": {"setup.py": "import WEBINSTALL", + "README": "WEB!"}}, + }, + "doc": {"historic": {"hello": "there"}, + "other": "contents", + }, + } + + outStructure = { + "bin": {"twistd": "TWISTD"}, + "twisted": + {"web": + {"__init__.py": "import WEB", + "topfiles": {"setup.py": "import WEBINSTALL", + "README": "WEB!"}}, + }, + "doc": {"other": "contents"}, + } + + self.createStructure(self.rootDir, structure) + outputFile = self.builder.buildTwisted("10.0.0") + self.assertExtractedStructure(outputFile, outStructure) + + def test_subProjectLayout(self): """ The subproject tarball includes files like so: @@ -2169,8 +2203,6 @@ howtoInput, howtoOutput = self.getArbitraryLoreInputAndOutput("8.0.0") specInput, specOutput = self.getArbitraryLoreInputAndOutput( "8.0.0", prefix="../howto/") - upgradeInput, upgradeOutput = self.getArbitraryLoreInputAndOutput( - "8.0.0", prefix="../howto/") tutorialInput, tutorialOutput = self.getArbitraryLoreInputAndOutput( "8.0.0", prefix="../") @@ -2192,7 +2224,6 @@ "tutorial": {"index.xhtml": tutorialInput}}, "specifications": {"index.xhtml": specInput}, - "upgrades": {"index.xhtml": upgradeInput}, "examples": {"foo.py": "foo.py"}, "index.xhtml": indexInput}, "web": {"howto": {"index.xhtml": "webindex"}}}, @@ -2214,7 +2245,6 @@ "index.html": howtoOutput, "tutorial": {"index.html": tutorialOutput}}, "specifications": {"index.html": specOutput}, - "upgrades": {"index.html": upgradeOutput}, "examples": {"foo.py": "foo.py"}, "index.html": indexOutput}, "bin": {"twistd": "TWISTD"}, @@ -2506,18 +2536,25 @@ def test_buildTarballsScript(self): """ L{BuildTarballsScript.main} invokes L{buildAllTarballs} with - L{FilePath} instances representing the paths passed to it. + 2 or 3 L{FilePath} instances representing the paths passed to it. """ builds = [] - def myBuilder(checkout, destination): - builds.append((checkout, destination)) + def myBuilder(checkout, destination, template=None): + builds.append((checkout, destination, template)) tarballBuilder = BuildTarballsScript() tarballBuilder.buildAllTarballs = myBuilder tarballBuilder.main(["checkoutDir", "destinationDir"]) self.assertEqual( builds, - [(FilePath("checkoutDir"), FilePath("destinationDir"))]) + [(FilePath("checkoutDir"), FilePath("destinationDir"), None)]) + + builds = [] + tarballBuilder.main(["checkoutDir", "destinationDir", "templatePath"]) + self.assertEqual( + builds, + [(FilePath("checkoutDir"), FilePath("destinationDir"), + FilePath("templatePath"))]) def test_defaultBuildTarballsScriptBuilder(self): @@ -2536,6 +2573,7 @@ """ tarballBuilder = BuildTarballsScript() self.assertRaises(SystemExit, tarballBuilder.main, []) + self.assertRaises(SystemExit, tarballBuilder.main, ["a", "b", "c", "d"]) def test_badNumberOfArgumentsToBuildNews(self): diff -Nru twisted-12.0.0/twisted/python/test/test_runtime.py twisted-12.2.0/twisted/python/test/test_runtime.py --- twisted-12.0.0/twisted/python/test/test_runtime.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_runtime.py 2012-05-27 09:22:59.000000000 +0000 @@ -5,13 +5,28 @@ Tests for runtime checks. """ +import sys - -from twisted.python.runtime import Platform +from twisted.python.runtime import Platform, shortPythonVersion from twisted.trial.unittest import TestCase +class PythonVersionTests(TestCase): + """ + Tests the shortPythonVersion method. + """ + + def test_shortPythonVersion(self): + """ + Verify if the Python version is returned correctly. + """ + ver = shortPythonVersion().split('.') + for i in range(3): + self.assertEqual(int(ver[i]), sys.version_info[i]) + + + class PlatformTests(TestCase): """ Tests for the default L{Platform} initializer. @@ -39,6 +54,16 @@ self.assertEqual(platform.getType(), 'posix') + def test_isLinuxConsistency(self): + """ + L{Platform.isLinux} can only return C{True} if L{Platform.getType} + returns C{'posix'} and L{sys.platform} starts with C{"linux"}. + """ + platform = Platform() + if platform.isLinux(): + self.assertTrue(sys.platform.startswith("linux")) + + class ForeignPlatformTests(TestCase): """ @@ -66,3 +91,16 @@ self.assertTrue(Platform(None, 'darwin').isMacOSX()) self.assertFalse(Platform(None, 'linux2').isMacOSX()) self.assertFalse(Platform(None, 'win32').isMacOSX()) + + + def test_isLinux(self): + """ + If a system platform name is supplied to L{Platform}'s initializer, it + is used to determine the result of L{Platform.isLinux}, which returns + C{True} for values beginning with C{"linux"}, C{False} otherwise. + """ + self.assertFalse(Platform(None, 'darwin').isLinux()) + self.assertTrue(Platform(None, 'linux').isLinux()) + self.assertTrue(Platform(None, 'linux2').isLinux()) + self.assertTrue(Platform(None, 'linux3').isLinux()) + self.assertFalse(Platform(None, 'win32').isLinux()) diff -Nru twisted-12.0.0/twisted/python/test/test_sendmsg.py twisted-12.2.0/twisted/python/test/test_sendmsg.py --- twisted-12.0.0/twisted/python/test/test_sendmsg.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_sendmsg.py 2012-04-14 10:02:04.000000000 +0000 @@ -0,0 +1,543 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.python.sendmsg}. +""" + +import sys +import errno + +from socket import SOL_SOCKET, AF_INET, AF_INET6, socket, error + +try: + from socket import AF_UNIX, socketpair +except ImportError: + nonUNIXSkip = "Platform does not support AF_UNIX sockets" +else: + nonUNIXSkip = None + +from struct import pack +from os import devnull, pipe, read, close, environ + +from twisted.internet.defer import Deferred +from twisted.internet.error import ProcessDone +from twisted.trial.unittest import TestCase +from twisted.internet.defer import inlineCallbacks +from twisted.internet import reactor +from twisted.python.filepath import FilePath +from twisted.python.runtime import platform + +from twisted.internet.protocol import ProcessProtocol + +if platform.isLinux(): + from socket import MSG_DONTWAIT + dontWaitSkip = None +else: + # It would be nice to be able to test flags on more platforms, but finding a + # flag that works *at all* is somewhat challenging. + dontWaitSkip = "MSG_DONTWAIT is only known to work as intended on Linux" + +try: + from twisted.python.sendmsg import SCM_RIGHTS, send1msg, recv1msg, getsockfam +except ImportError: + importSkip = "Cannot import twisted.python.sendmsg" +else: + importSkip = None + + +class ExitedWithStderr(Exception): + """ + A process exited with some stderr. + """ + + def __str__(self): + """ + Dump the errors in a pretty way in the event of a subprocess traceback. + """ + return '\n'.join([''] + list(self.args)) + + +class StartStopProcessProtocol(ProcessProtocol): + """ + An L{IProcessProtocol} with a Deferred for events where the subprocess + starts and stops. + + @ivar started: A L{Deferred} which fires with this protocol's + L{IProcessTransport} provider when it is connected to one. + + @ivar stopped: A L{Deferred} which fires with the process output or a + failure if the process produces output on standard error. + + @ivar output: A C{str} used to accumulate standard output. + + @ivar errors: A C{str} used to accumulate standard error. + """ + def __init__(self): + self.started = Deferred() + self.stopped = Deferred() + self.output = '' + self.errors = '' + + + def connectionMade(self): + self.started.callback(self.transport) + + + def outReceived(self, data): + self.output += data + + + def errReceived(self, data): + self.errors += data + + + def processEnded(self, reason): + if reason.check(ProcessDone): + self.stopped.callback(self.output) + else: + self.stopped.errback(ExitedWithStderr( + self.errors, self.output)) + + + +class BadList(list): + """ + A list which cannot be iterated sometimes. + + This is a C{list} subclass to get past the type check in L{send1msg}, not as + an example of how real programs might want to interact with L{send1msg} (or + anything else). A custom C{list} subclass makes it easier to trigger + certain error cases in the implementation. + + @ivar iterate: A flag which indicates whether an instance of L{BadList} will + allow iteration over itself or not. If C{False}, an attempt to iterate + over the instance will raise an exception. + """ + iterate = True + + def __iter__(self): + """ + Allow normal list iteration, or raise an exception. + + If C{self.iterate} is C{True}, it will be flipped to C{False} and then + normal iteration will proceed. If C{self.iterate} is C{False}, + L{RuntimeError} is raised instead. + """ + if self.iterate: + self.iterate = False + return super(BadList, self).__iter__() + raise RuntimeError("Something bad happened") + + + +class WorseList(list): + """ + A list which at first gives the appearance of being iterable, but then + raises an exception. + + See L{BadList} for a warning about not writing code like this. + """ + def __iter__(self): + """ + Return an iterator which will raise an exception as soon as C{next} is + called on it. + """ + class BadIterator(object): + def next(self): + raise RuntimeError("This is a really bad case.") + return BadIterator() + + + +class SendmsgTestCase(TestCase): + """ + Tests for sendmsg extension module and associated file-descriptor sending + functionality. + """ + if nonUNIXSkip is not None: + skip = nonUNIXSkip + elif importSkip is not None: + skip = importSkip + + def setUp(self): + """ + Create a pair of UNIX sockets. + """ + self.input, self.output = socketpair(AF_UNIX) + + + def tearDown(self): + """ + Close the sockets opened by setUp. + """ + self.input.close() + self.output.close() + + + def test_sendmsgBadArguments(self): + """ + The argument types accepted by L{send1msg} are: + + 1. C{int} + 2. read-only character buffer + 3. C{int} + 4. sequence + + The 3rd and 4th arguments are optional. If fewer than two arguments or + more than four arguments are passed, or if any of the arguments passed + are not compatible with these types, L{TypeError} is raised. + """ + # Exercise the wrong number of arguments cases + self.assertRaises(TypeError, send1msg) + self.assertRaises(TypeError, send1msg, 1) + self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [], object()) + + # Exercise the wrong type of arguments cases + self.assertRaises(TypeError, send1msg, object(), "hello world", 2, []) + self.assertRaises(TypeError, send1msg, 1, object(), 2, []) + self.assertRaises(TypeError, send1msg, 1, "hello world", object(), []) + self.assertRaises(TypeError, send1msg, 1, "hello world", 2, object()) + + + def test_badAncillaryIter(self): + """ + If iteration over the ancillary data list fails (at the point of the + C{__iter__} call), the exception with which it fails is propagated to + the caller of L{send1msg}. + """ + badList = BadList() + badList.append((1, 2, "hello world")) + badList.iterate = False + + self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, badList) + + # Hit the second iteration + badList.iterate = True + self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, badList) + + + def test_badAncillaryNext(self): + """ + If iteration over the ancillary data list fails (at the point of a + C{next} call), the exception with which it fails is propagated to the + caller of L{send1msg}. + """ + worseList = WorseList() + self.assertRaises(RuntimeError, send1msg, 1, "hello world", 2, worseList) + + + def test_sendmsgBadAncillaryItem(self): + """ + The ancillary data list contains three-tuples with element types of: + + 1. C{int} + 2. C{int} + 3. read-only character buffer + + If a tuple in the ancillary data list does not elements of these types, + L{TypeError} is raised. + """ + # Exercise the wrong number of arguments cases + self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [()]) + self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [(1,)]) + self.assertRaises(TypeError, send1msg, 1, "hello world", 2, [(1, 2)]) + self.assertRaises( + TypeError, + send1msg, 1, "hello world", 2, [(1, 2, "goodbye", object())]) + + # Exercise the wrong type of arguments cases + exc = self.assertRaises( + TypeError, send1msg, 1, "hello world", 2, [object()]) + self.assertEqual( + "send1msg argument 3 expected list of tuple, " + "got list containing object", + str(exc)) + self.assertRaises( + TypeError, + send1msg, 1, "hello world", 2, [(object(), 1, "goodbye")]) + self.assertRaises( + TypeError, + send1msg, 1, "hello world", 2, [(1, object(), "goodbye")]) + self.assertRaises( + TypeError, + send1msg, 1, "hello world", 2, [(1, 1, object())]) + + + def test_syscallError(self): + """ + If the underlying C{sendmsg} call fails, L{send1msg} raises + L{socket.error} with its errno set to the underlying errno value. + """ + probe = file(devnull) + fd = probe.fileno() + probe.close() + exc = self.assertRaises(error, send1msg, fd, "hello, world") + self.assertEqual(exc.args[0], errno.EBADF) + + + def test_syscallErrorWithControlMessage(self): + """ + The behavior when the underlying C{sendmsg} call fails is the same + whether L{send1msg} is passed ancillary data or not. + """ + probe = file(devnull) + fd = probe.fileno() + probe.close() + exc = self.assertRaises( + error, send1msg, fd, "hello, world", 0, [(0, 0, "0123")]) + self.assertEqual(exc.args[0], errno.EBADF) + + + def test_roundtrip(self): + """ + L{recv1msg} will retrieve a message sent via L{send1msg}. + """ + message = "hello, world!" + self.assertEqual( + len(message), + send1msg(self.input.fileno(), message, 0)) + + result = recv1msg(fd=self.output.fileno()) + self.assertEquals(result, (message, 0, [])) + + + def test_shortsend(self): + """ + L{send1msg} returns the number of bytes which it was able to send. + """ + message = "x" * 1024 * 1024 + self.input.setblocking(False) + sent = send1msg(self.input.fileno(), message) + # Sanity check - make sure we did fill the send buffer and then some + self.assertTrue(sent < len(message)) + received = recv1msg(self.output.fileno(), 0, len(message)) + self.assertEqual(len(received[0]), sent) + + + def test_roundtripEmptyAncillary(self): + """ + L{send1msg} treats an empty ancillary data list the same way it treats + receiving no argument for the ancillary parameter at all. + """ + send1msg(self.input.fileno(), "hello, world!", 0, []) + + result = recv1msg(fd=self.output.fileno()) + self.assertEquals(result, ("hello, world!", 0, [])) + + + def test_flags(self): + """ + The C{flags} argument to L{send1msg} is passed on to the underlying + C{sendmsg} call, to affect it in whatever way is defined by those flags. + """ + # Just exercise one flag with simple, well-known behavior. MSG_DONTWAIT + # makes the send a non-blocking call, even if the socket is in blocking + # mode. See also test_flags in RecvmsgTestCase + for i in range(1024): + try: + send1msg(self.input.fileno(), "x" * 1024, MSG_DONTWAIT) + except error, e: + self.assertEqual(e.args[0], errno.EAGAIN) + break + else: + self.fail( + "Failed to fill up the send buffer, " + "or maybe send1msg blocked for a while") + if dontWaitSkip is not None: + test_flags.skip = dontWaitSkip + + + def test_wrongTypeAncillary(self): + """ + L{send1msg} will show a helpful exception message when given the wrong + type of object for the 'ancillary' argument. + """ + error = self.assertRaises(TypeError, + send1msg, self.input.fileno(), + "hello, world!", 0, 4321) + self.assertEquals(str(error), + "send1msg argument 3 expected list, got int") + + + def spawn(self, script): + """ + Start a script that is a peer of this test as a subprocess. + + @param script: the module name of the script in this directory (no + package prefix, no '.py') + @type script: C{str} + + @rtype: L{StartStopProcessProtocol} + """ + sspp = StartStopProcessProtocol() + reactor.spawnProcess( + sspp, sys.executable, [ + sys.executable, + FilePath(__file__).sibling(script + ".py").path, + str(self.output.fileno()), + ], + environ, + childFDs={0: "w", 1: "r", 2: "r", + self.output.fileno(): self.output.fileno()} + ) + return sspp + + + @inlineCallbacks + def test_sendSubProcessFD(self): + """ + Calling L{sendsmsg} with SOL_SOCKET, SCM_RIGHTS, and a platform-endian + packed file descriptor number should send that file descriptor to a + different process, where it can be retrieved by using L{recv1msg}. + """ + sspp = self.spawn("pullpipe") + yield sspp.started + pipeOut, pipeIn = pipe() + self.addCleanup(close, pipeOut) + + send1msg( + self.input.fileno(), "blonk", 0, + [(SOL_SOCKET, SCM_RIGHTS, pack("i", pipeIn))]) + + close(pipeIn) + yield sspp.stopped + self.assertEquals(read(pipeOut, 1024), "Test fixture data: blonk.\n") + # Make sure that the pipe is actually closed now. + self.assertEquals(read(pipeOut, 1024), "") + + + +class RecvmsgTestCase(TestCase): + """ + Tests for L{recv1msg} (primarily error handling cases). + """ + if importSkip is not None: + skip = importSkip + + def test_badArguments(self): + """ + The argument types accepted by L{recv1msg} are: + + 1. C{int} + 2. C{int} + 3. C{int} + 4. C{int} + + The 2nd, 3rd, and 4th arguments are optional. If fewer than one + argument or more than four arguments are passed, or if any of the + arguments passed are not compatible with these types, L{TypeError} is + raised. + """ + # Exercise the wrong number of arguments cases + self.assertRaises(TypeError, recv1msg) + self.assertRaises(TypeError, recv1msg, 1, 2, 3, 4, object()) + + # Exercise the wrong type of arguments cases + self.assertRaises(TypeError, recv1msg, object(), 2, 3, 4) + self.assertRaises(TypeError, recv1msg, 1, object(), 3, 4) + self.assertRaises(TypeError, recv1msg, 1, 2, object(), 4) + self.assertRaises(TypeError, recv1msg, 1, 2, 3, object()) + + + def test_cmsgSpaceOverflow(self): + """ + L{recv1msg} raises L{OverflowError} if passed a value for the + C{cmsg_size} argument which exceeds C{SOCKLEN_MAX}. + """ + self.assertRaises(OverflowError, recv1msg, 0, 0, 0, 0x7FFFFFFF) + + + def test_syscallError(self): + """ + If the underlying C{recvmsg} call fails, L{recv1msg} raises + L{socket.error} with its errno set to the underlying errno value. + """ + probe = file(devnull) + fd = probe.fileno() + probe.close() + exc = self.assertRaises(error, recv1msg, fd) + self.assertEqual(exc.args[0], errno.EBADF) + + + def test_flags(self): + """ + The C{flags} argument to L{recv1msg} is passed on to the underlying + C{recvmsg} call, to affect it in whatever way is defined by those flags. + """ + # See test_flags in SendmsgTestCase + reader, writer = socketpair(AF_UNIX) + exc = self.assertRaises( + error, recv1msg, reader.fileno(), MSG_DONTWAIT) + self.assertEqual(exc.args[0], errno.EAGAIN) + if dontWaitSkip is not None: + test_flags.skip = dontWaitSkip + + + +class GetSocketFamilyTests(TestCase): + """ + Tests for L{getsockfam}, a helper which reveals the address family of an + arbitrary socket. + """ + if importSkip is not None: + skip = importSkip + + def _socket(self, addressFamily): + """ + Create a new socket using the given address family and return that + socket's file descriptor. The socket will automatically be closed when + the test is torn down. + """ + s = socket(addressFamily) + self.addCleanup(s.close) + return s.fileno() + + + def test_badArguments(self): + """ + L{getsockfam} accepts a single C{int} argument. If it is called in some + other way, L{TypeError} is raised. + """ + self.assertRaises(TypeError, getsockfam) + self.assertRaises(TypeError, getsockfam, 1, 2) + + self.assertRaises(TypeError, getsockfam, object()) + + + def test_syscallError(self): + """ + If the underlying C{getsockname} call fails, L{getsockfam} raises + L{socket.error} with its errno set to the underlying errno value. + """ + probe = file(devnull) + fd = probe.fileno() + probe.close() + exc = self.assertRaises(error, getsockfam, fd) + self.assertEqual(errno.EBADF, exc.args[0]) + + + def test_inet(self): + """ + When passed the file descriptor of a socket created with the C{AF_INET} + address family, L{getsockfam} returns C{AF_INET}. + """ + self.assertEqual(AF_INET, getsockfam(self._socket(AF_INET))) + + + def test_inet6(self): + """ + When passed the file descriptor of a socket created with the C{AF_INET6} + address family, L{getsockfam} returns C{AF_INET6}. + """ + self.assertEqual(AF_INET6, getsockfam(self._socket(AF_INET6))) + + + def test_unix(self): + """ + When passed the file descriptor of a socket created with the C{AF_UNIX} + address family, L{getsockfam} returns C{AF_UNIX}. + """ + self.assertEqual(AF_UNIX, getsockfam(self._socket(AF_UNIX))) + if nonUNIXSkip is not None: + test_unix.skip = nonUNIXSkip diff -Nru twisted-12.0.0/twisted/python/test/test_systemd.py twisted-12.2.0/twisted/python/test/test_systemd.py --- twisted-12.0.0/twisted/python/test/test_systemd.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_systemd.py 2012-04-04 21:03:05.000000000 +0000 @@ -0,0 +1,173 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.python.systemd}. +""" + +import os + +from twisted.trial.unittest import TestCase +from twisted.python.systemd import ListenFDs + + +class InheritedDescriptorsMixin(object): + """ + Mixin for a L{TestCase} subclass which defines test methods for some kind of + systemd sd-daemon class. In particular, it defines tests for a + C{inheritedDescriptors} method. + """ + def test_inheritedDescriptors(self): + """ + C{inheritedDescriptors} returns a list of integers giving the file + descriptors which were inherited from systemd. + """ + sddaemon = self.getDaemon(7, 3) + self.assertEqual([7, 8, 9], sddaemon.inheritedDescriptors()) + + + def test_repeated(self): + """ + Any subsequent calls to C{inheritedDescriptors} return the same list. + """ + sddaemon = self.getDaemon(7, 3) + self.assertEqual( + sddaemon.inheritedDescriptors(), + sddaemon.inheritedDescriptors()) + + + +class MemoryOnlyMixin(object): + """ + Mixin for a L{TestCase} subclass which creates creating a fake, in-memory + implementation of C{inheritedDescriptors}. This provides verification that + the fake behaves in a compatible way with the real implementation. + """ + def getDaemon(self, start, count): + """ + Invent C{count} new I{file descriptors} (actually integers, attached to + no real file description), starting at C{start}. Construct and return a + new L{ListenFDs} which will claim those integers represent inherited + file descriptors. + """ + return ListenFDs(range(start, start + count)) + + + +class EnvironmentMixin(object): + """ + Mixin for a L{TestCase} subclass which creates a real implementation of + C{inheritedDescriptors} which is based on the environment variables set by + systemd. To facilitate testing, this mixin will also create a fake + environment dictionary and add keys to it to make it look as if some + descriptors have been inherited. + """ + def initializeEnvironment(self, count, pid): + """ + Create a copy of the process environment and add I{LISTEN_FDS} and + I{LISTEN_PID} (the environment variables set by systemd) to it. + """ + result = os.environ.copy() + result['LISTEN_FDS'] = str(count) + result['LISTEN_PID'] = str(pid) + return result + + + def getDaemon(self, start, count): + """ + Create a new L{ListenFDs} instance, initialized with a fake environment + dictionary which will be set up as systemd would have set it up if + C{count} descriptors were being inherited. The descriptors will also + start at C{start}. + """ + fakeEnvironment = self.initializeEnvironment(count, os.getpid()) + return ListenFDs.fromEnvironment(environ=fakeEnvironment, start=start) + + + +class MemoryOnlyTests(MemoryOnlyMixin, InheritedDescriptorsMixin, TestCase): + """ + Apply tests to L{ListenFDs}, explicitly constructed with some fake file + descriptors. + """ + + + +class EnvironmentTests(EnvironmentMixin, InheritedDescriptorsMixin, TestCase): + """ + Apply tests to L{ListenFDs}, constructed based on an environment dictionary. + """ + def test_secondEnvironment(self): + """ + Only a single L{Environment} can extract inherited file descriptors. + """ + fakeEnvironment = self.initializeEnvironment(3, os.getpid()) + first = ListenFDs.fromEnvironment(environ=fakeEnvironment) + second = ListenFDs.fromEnvironment(environ=fakeEnvironment) + self.assertEqual(range(3, 6), first.inheritedDescriptors()) + self.assertEqual([], second.inheritedDescriptors()) + + + def test_mismatchedPID(self): + """ + If the current process PID does not match the PID in the environment, no + inherited descriptors are reported. + """ + fakeEnvironment = self.initializeEnvironment(3, os.getpid() + 1) + sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) + self.assertEqual([], sddaemon.inheritedDescriptors()) + + + def test_missingPIDVariable(self): + """ + If the I{LISTEN_PID} environment variable is not present, no inherited + descriptors are reported. + """ + fakeEnvironment = self.initializeEnvironment(3, os.getpid()) + del fakeEnvironment['LISTEN_PID'] + sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) + self.assertEqual([], sddaemon.inheritedDescriptors()) + + + def test_nonIntegerPIDVariable(self): + """ + If the I{LISTEN_PID} environment variable is set to a string that cannot + be parsed as an integer, no inherited descriptors are reported. + """ + fakeEnvironment = self.initializeEnvironment(3, "hello, world") + sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) + self.assertEqual([], sddaemon.inheritedDescriptors()) + + + def test_missingFDSVariable(self): + """ + If the I{LISTEN_FDS} environment variable is not present, no inherited + descriptors are reported. + """ + fakeEnvironment = self.initializeEnvironment(3, os.getpid()) + del fakeEnvironment['LISTEN_FDS'] + sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) + self.assertEqual([], sddaemon.inheritedDescriptors()) + + + def test_nonIntegerFDSVariable(self): + """ + If the I{LISTEN_FDS} environment variable is set to a string that cannot + be parsed as an integer, no inherited descriptors are reported. + """ + fakeEnvironment = self.initializeEnvironment("hello, world", os.getpid()) + sddaemon = ListenFDs.fromEnvironment(environ=fakeEnvironment) + self.assertEqual([], sddaemon.inheritedDescriptors()) + + + def test_defaultEnviron(self): + """ + If the process environment is not explicitly passed to + L{Environment.__init__}, the real process environment dictionary is + used. + """ + self.patch(os, 'environ', { + 'LISTEN_PID': str(os.getpid()), + 'LISTEN_FDS': '5'}) + sddaemon = ListenFDs.fromEnvironment() + self.assertEqual(range(3, 3 + 5), sddaemon.inheritedDescriptors()) diff -Nru twisted-12.0.0/twisted/python/test/test_util.py twisted-12.2.0/twisted/python/test/test_util.py --- twisted-12.0.0/twisted/python/test/test_util.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_util.py 2012-06-19 17:27:25.000000000 +0000 @@ -119,20 +119,6 @@ "Group Name/GID conversion requires the grp module.") - def test_moduleMovedForSplitDeprecation(self): - """ - Calling L{moduleMovedForSplit} results in a deprecation warning. - """ - util.moduleMovedForSplit("foo", "bar", "baz", "quux", "corge", {}) - warnings = self.flushWarnings( - offendingFunctions=[self.test_moduleMovedForSplitDeprecation]) - self.assertEqual( - warnings[0]['message'], - "moduleMovedForSplit is deprecated since Twisted 9.0.") - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual(len(warnings), 1) - - class SwitchUIDTest(unittest.TestCase): """ @@ -434,26 +420,6 @@ expected=None self.assertEqual(actual, expected) -class Foo: - def __init__(self, x): - self.x = x - -class DSU(unittest.TestCase): - """ - Tests for L{util.dsu} - """ - def test_dsu(self): - L = [Foo(x) for x in range(20, 9, -1)] - L2 = util.dsu(L, lambda o: o.x) - self.assertEqual(range(10, 21), [o.x for o in L2]) - - - def test_deprecation(self): - self.assertWarns(DeprecationWarning, - ("dsu is deprecated since Twisted 10.1. " - "Use the built-in sorted() instead."), - __file__, lambda: util.dsu([], lambda: 0)) - class IntervalDifferentialTestCase(unittest.TestCase): @@ -924,3 +890,39 @@ if util._c_initgroups is None: test_initgroupsInC.skip = "C initgroups not available" + + +class DeprecationTests(unittest.TestCase): + """ + Tests for deprecations in C{twisted.python.util}. + """ + def test_getPluginDirs(self): + """ + L{util.getPluginDirs} is deprecated. + """ + util.getPluginDirs() + warnings = self.flushWarnings(offendingFunctions=[ + self.test_getPluginDirs]) + self.assertEqual( + warnings[0]['message'], + "twisted.python.util.getPluginDirs is deprecated since Twisted " + "12.2.") + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) + + + def test_addPluginDir(self): + """ + L{util.addPluginDir} is deprecated. + """ + util.addPluginDir() + warnings = self.flushWarnings(offendingFunctions=[ + self.test_addPluginDir]) + self.assertEqual( + warnings[0]['message'], + "twisted.python.util.addPluginDir is deprecated since Twisted " + "12.2.") + self.assertEqual(warnings[0]['category'], DeprecationWarning) + self.assertEqual(len(warnings), 1) + + diff -Nru twisted-12.0.0/twisted/python/test/test_zipstream.py twisted-12.2.0/twisted/python/test/test_zipstream.py --- twisted-12.0.0/twisted/python/test/test_zipstream.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/python/test/test_zipstream.py 2012-08-08 20:17:02.000000000 +0000 @@ -4,6 +4,7 @@ """ Tests for L{twisted.python.zipstream} """ + import sys import random import zipfile @@ -11,7 +12,8 @@ from twisted.python.compat import set from twisted.python import zipstream, filepath from twisted.python.hashlib import md5 -from twisted.trial import unittest, util +from twisted.trial import unittest + class FileEntryMixin: """ @@ -167,19 +169,6 @@ return zpfilename - def test_countEntries(self): - """ - Make sure the deprecated L{countZipFileEntries} returns the correct - number of entries for a zip file. - """ - name = self.makeZipFile(["one", "two", "three", "four", "five"]) - result = self.assertWarns(DeprecationWarning, - "countZipFileEntries is deprecated.", - __file__, lambda : - zipstream.countZipFileEntries(name)) - self.assertEqual(result, 5) - - def test_invalidMode(self): """ A ChunkingZipFile opened in write-mode should not allow .readfile(), @@ -283,49 +272,6 @@ self.assertEqual(czf.readfile("0").read(), "the real data") - def test_unzipIter(self): - """ - L{twisted.python.zipstream.unzipIter} should unzip a file for each - iteration and yield the number of files left to unzip after that - iteration - """ - numfiles = 10 - contents = ['This is test file %d!' % i for i in range(numfiles)] - zpfilename = self.makeZipFile(contents) - uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path) - for i in range(numfiles): - self.assertEqual(len(list(self.unzipdir.children())), i) - self.assertEqual(uziter.next(), numfiles - i - 1) - self.assertEqual(len(list(self.unzipdir.children())), numfiles) - - for child in self.unzipdir.children(): - num = int(child.basename()) - self.assertEqual(child.open().read(), contents[num]) - test_unzipIter.suppress = [ - util.suppress(message="zipstream.unzipIter is deprecated")] - - - def test_unzipIterDeprecated(self): - """ - Use of C{twisted.python.zipstream.unzipIter} will emit a - deprecated warning. - """ - zpfilename = self.makeZipFile('foo') - - self.assertEqual(len(self.flushWarnings()), 0) - - for f in zipstream.unzipIter(zpfilename, self.unzipdir.path): - pass - - warnings = self.flushWarnings() - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "zipstream.unzipIter is deprecated since Twisted 11.0.0 for " - "security reasons. Use Python's zipfile instead.") - - def test_unzipIterChunky(self): """ L{twisted.python.zipstream.unzipIterChunky} returns an iterator which @@ -363,89 +309,6 @@ self.assertEqual(child.getContent(), contents[num]) - def test_unzip(self): - """ - L{twisted.python.zipstream.unzip} should extract all files from a zip - archive - """ - numfiles = 3 - zpfilename = self.makeZipFile([str(i) for i in range(numfiles)]) - zipstream.unzip(zpfilename, self.unzipdir.path) - self.assertEqual( - set(self.unzipdir.listdir()), - set(map(str, range(numfiles)))) - for i in range(numfiles): - self.assertEqual(self.unzipdir.child(str(i)).getContent(), str(i)) - test_unzip.suppress = [ - util.suppress(message="zipstream.unzip is deprecated")] - - - def test_unzipDeprecated(self): - """ - Use of C{twisted.python.zipstream.unzip} will emit a deprecated warning. - """ - zpfilename = self.makeZipFile('foo') - - self.assertEqual(len(self.flushWarnings()), 0) - - zipstream.unzip(zpfilename, self.unzipdir.path) - - warnings = self.flushWarnings() - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "zipstream.unzip is deprecated since Twisted 11.0.0 for " - "security reasons. Use Python's zipfile instead.") - - - def test_unzipDirectory(self): - """ - The path to which a file is extracted by L{zipstream.unzip} is - determined by joining the C{directory} argument to C{unzip} with the - path within the archive of the file being extracted. - """ - numfiles = 3 - zpfilename = self.makeZipFile([str(i) for i in range(numfiles)], 'foo') - zipstream.unzip(zpfilename, self.unzipdir.path) - self.assertEqual( - set(self.unzipdir.child('foo').listdir()), - set(map(str, range(numfiles)))) - for i in range(numfiles): - self.assertEqual( - self.unzipdir.child('foo').child(str(i)).getContent(), str(i)) - test_unzipDirectory.suppress = [ - util.suppress(message="zipstream.unzip is deprecated")] - - - def test_overwrite(self): - """ - L{twisted.python.zipstream.unzip} and - L{twisted.python.zipstream.unzipIter} shouldn't overwrite files unless - the 'overwrite' flag is passed - """ - testfile = self.unzipdir.child('0') - zpfilename = self.makeZipFile(['OVERWRITTEN']) - - testfile.setContent('NOT OVERWRITTEN') - zipstream.unzip(zpfilename, self.unzipdir.path) - self.assertEqual(testfile.open().read(), 'NOT OVERWRITTEN') - zipstream.unzip(zpfilename, self.unzipdir.path, overwrite=True) - self.assertEqual(testfile.open().read(), 'OVERWRITTEN') - - testfile.setContent('NOT OVERWRITTEN') - uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path) - uziter.next() - self.assertEqual(testfile.open().read(), 'NOT OVERWRITTEN') - uziter = zipstream.unzipIter(zpfilename, self.unzipdir.path, - overwrite=True) - uziter.next() - self.assertEqual(testfile.open().read(), 'OVERWRITTEN') - test_overwrite.suppress = [ - util.suppress(message="zipstream.unzip is deprecated"), - util.suppress(message="zipstream.unzipIter is deprecated")] - - # XXX these tests are kind of gross and old, but I think unzipIterChunky is # kind of a gross function anyway. We should really write an abstract # copyTo/moveTo that operates on FilePath and make sure ZipPath can support diff -Nru twisted-12.0.0/twisted/python/text.py twisted-12.2.0/twisted/python/text.py --- twisted-12.0.0/twisted/python/text.py 2011-06-08 23:11:41.000000000 +0000 +++ twisted-12.2.0/twisted/python/text.py 2012-08-14 08:03:17.000000000 +0000 @@ -3,31 +3,26 @@ # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - """ Miscellany of text-munging functions. """ -import string, types - -from twisted.python import deprecate, versions - def stringyString(object, indentation=''): """ Expansive string formatting for sequence types. - list.__str__ and dict.__str__ use repr() to display their + C{list.__str__} and C{dict.__str__} use C{repr()} to display their elements. This function also turns these sequence types - into strings, but uses str() on their elements instead. + into strings, but uses C{str()} on their elements instead. - Sequence elements are also displayed on seperate lines, - and nested sequences have nested indentation. + Sequence elements are also displayed on seperate lines, and nested + sequences have nested indentation. """ braces = '' sl = [] - if type(object) is types.DictType: + if type(object) is dict: braces = '{}' for key, value in object.items(): value = stringyString(value, indentation + ' ') @@ -40,18 +35,18 @@ sl.append("%s %s: %s" % (indentation, key, value[len(indentation) + 3:])) - elif type(object) in (types.TupleType, types.ListType): - if type(object) is types.TupleType: + elif type(object) is tuple or type(object) is list: + if type(object) is tuple: braces = '()' else: braces = '[]' for element in object: element = stringyString(element, indentation + ' ') - sl.append(string.rstrip(element) + ',') + sl.append(element.rstrip() + ',') else: - sl[:] = map(lambda s, i=indentation: i+s, - string.split(str(object),'\n')) + sl[:] = map(lambda s, i=indentation: i + s, + str(object).split('\n')) if not sl: sl.append(indentation) @@ -60,67 +55,31 @@ sl[0] = indentation + braces[0] + sl[0][len(indentation) + 1:] sl[-1] = sl[-1] + braces[-1] - s = string.join(sl, "\n") + s = "\n".join(sl) if isMultiline(s) and not endsInNewline(s): s = s + '\n' return s -def isMultiline(s): - """Returns True if this string has a newline in it.""" - return (string.find(s, '\n') != -1) - -def endsInNewline(s): - """Returns True if this string ends in a newline.""" - return (s[-len('\n'):] == '\n') - - -deprecate.deprecatedModuleAttribute( - versions.Version("Twisted", 10, 2, 0), - "Please use inspect.getdoc instead.", - __name__, "docstringLStrip") - - - -def docstringLStrip(docstring): +def isMultiline(s): """ - Gets rid of unsightly lefthand docstring whitespace residue. - - You'd think someone would have done this already, but apparently - not in 1.5.2. - - BUT since we're all using Python 2.1 now, use L{inspect.getdoc} - instead. I{This function should go away soon.} + Returns C{True} if this string has a newline in it. """ + return (s.find('\n') != -1) - if not docstring: - return docstring - docstring = string.replace(docstring, '\t', ' ' * 8) - lines = string.split(docstring,'\n') - - leading = 0 - for l in xrange(1,len(lines)): - line = lines[l] - if string.strip(line): - while 1: - if line[leading] == ' ': - leading = leading + 1 - else: - break - if leading: - break - - outlines = lines[0:1] - for l in xrange(1,len(lines)): - outlines.append(lines[l][leading:]) +def endsInNewline(s): + """ + Returns C{True} if this string ends in a newline. + """ + return (s[-len('\n'):] == '\n') - return string.join(outlines, '\n') def greedyWrap(inString, width=80): - """Given a string and a column width, return a list of lines. + """ + Given a string and a column width, return a list of lines. Caveat: I'm use a stupid greedy word-wrapping algorythm. I won't put two spaces at the end @@ -132,11 +91,11 @@ #eww, evil hacks to allow paragraphs delimited by two \ns :( if inString.find('\n\n') >= 0: - paragraphs = string.split(inString, '\n\n') + paragraphs = inString.split('\n\n') for para in paragraphs: outLines.extend(greedyWrap(para, width) + ['']) return outLines - inWords = string.split(inString) + inWords = inString.split() column = 0 ptr_line = 0 @@ -152,13 +111,13 @@ # We've gone too far, stop the line one word back. ptr_line = ptr_line - 1 (l, inWords) = (inWords[0:ptr_line], inWords[ptr_line:]) - outLines.append(string.join(l,' ')) + outLines.append(' '.join(l)) ptr_line = 0 column = 0 elif not (len(inWords) > ptr_line): # Clean up the last bit. - outLines.append(string.join(inWords, ' ')) + outLines.append(' '.join(inWords)) del inWords[:] else: # Space @@ -170,6 +129,7 @@ wordWrap = greedyWrap + def removeLeadingBlanks(lines): ret = [] for line in lines: @@ -177,6 +137,7 @@ ret.append(line) return ret + def removeLeadingTrailingBlanks(s): lines = removeLeadingBlanks(s.split('\n')) lines.reverse() @@ -184,14 +145,16 @@ lines.reverse() return '\n'.join(lines)+'\n' + def splitQuoted(s): - """Like string.split, but don't break substrings inside quotes. + """ + Like a string split, but don't break substrings inside quotes. - >>> splitQuoted('the \"hairy monkey\" likes pie') + >>> splitQuoted('the "hairy monkey" likes pie') ['the', 'hairy monkey', 'likes', 'pie'] - Another one of those \"someone must have a better solution for - this\" things. This implementation is a VERY DUMB hack done too + Another one of those "someone must have a better solution for + this" things. This implementation is a VERY DUMB hack done too quickly. """ out = [] @@ -217,8 +180,11 @@ return out + def strFile(p, f, caseSensitive=True): - """Find whether string p occurs in a read()able object f + """ + Find whether string C{p} occurs in a read()able object C{f}. + @rtype: C{bool} """ buf = "" diff -Nru twisted-12.0.0/twisted/python/threadpool.py twisted-12.2.0/twisted/python/threadpool.py --- twisted-12.0.0/twisted/python/threadpool.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/python/threadpool.py 2012-02-11 11:29:31.000000000 +0000 @@ -2,26 +2,19 @@ # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - """ -twisted.threadpool: a pool of threads to which we dispatch tasks. +twisted.python.threadpool: a pool of threads to which we dispatch tasks. -In most cases you can just use reactor.callInThread and friends +In most cases you can just use C{reactor.callInThread} and friends instead of creating a thread pool directly. """ -# System Imports import Queue import threading import copy -import sys -import warnings - -# Twisted Imports from twisted.python import log, context, failure -from twisted.python.deprecate import deprecatedModuleAttribute -from twisted.python.versions import Version + WorkerStop = object() @@ -31,9 +24,9 @@ This class (hopefully) generalizes the functionality of a pool of threads to which work can be dispatched. - callInThread() and stop() should only be called from - a single thread, unless you make a subclass where stop() and - _startSomeWorkers() are synchronized. + L{callInThread} and L{stop} should only be called from + a single thread, unless you make a subclass where L{stop} and + L{_startSomeWorkers} are synchronized. """ min = 5 max = 20 @@ -50,7 +43,6 @@ Create a new threadpool. @param minthreads: minimum number of threads in the pool - @param maxthreads: maximum number of threads in the pool """ assert minthreads >= 0, 'minimum is negative' @@ -63,6 +55,7 @@ self.threads = [] self.working = [] + def start(self): """ Start the threadpool. @@ -72,6 +65,7 @@ # Start some threads. self.adjustPoolsize() + def startAWorker(self): self.workers += 1 name = "PoolThread-%s-%s" % (self.name or id(self), self.workers) @@ -79,20 +73,24 @@ self.threads.append(newThread) newThread.start() + def stopAWorker(self): self.q.put(WorkerStop) self.workers -= 1 + def __setstate__(self, state): self.__dict__ = state ThreadPool.__init__(self, self.min, self.max) + def __getstate__(self): state = {} state['min'] = self.min state['max'] = self.max return state + def _startSomeWorkers(self): neededSize = self.q.qsize() + len(self.working) # Create enough, but not too many @@ -100,60 +98,48 @@ self.startAWorker() - def dispatch(self, owner, func, *args, **kw): - """ - DEPRECATED: use L{callInThread} instead. - - Dispatch a function to be a run in a thread. - """ - warnings.warn("dispatch() is deprecated since Twisted 8.0, " - "use callInThread() instead", - DeprecationWarning, stacklevel=2) - self.callInThread(func, *args, **kw) - - def callInThread(self, func, *args, **kw): """ Call a callable object in a separate thread. @param func: callable object to be called in separate thread - @param *args: positional arguments to be passed to func + @param *args: positional arguments to be passed to C{func} - @param **kw: keyword args to be passed to func + @param **kw: keyword args to be passed to C{func} """ self.callInThreadWithCallback(None, func, *args, **kw) def callInThreadWithCallback(self, onResult, func, *args, **kw): """ - Call a callable object in a separate thread and call onResult + Call a callable object in a separate thread and call C{onResult} with the return value, or a L{twisted.python.failure.Failure} if the callable raises an exception. - The callable is allowed to block, but the onResult function + The callable is allowed to block, but the C{onResult} function must not block and should perform as little work as possible. - A typical action for onResult for a threadpool used with a - Twisted reactor would be to schedule a Deferred to fire in the - main reactor thread using C{.callFromThread}. Note that - onResult is called inside the separate thread, not inside the - reactor thread. - - @param onResult: a callable with the signature (success, result). - If the callable returns normally, onResult is called with - (True, result) where result is the return value of the callable. - If the callable throws an exception, onResult is called with - (False, failure). + A typical action for C{onResult} for a threadpool used with a + Twisted reactor would be to schedule a + L{twisted.internet.defer.Deferred} to fire in the main + reactor thread using C{.callFromThread}. Note that C{onResult} + is called inside the separate thread, not inside the reactor thread. + + @param onResult: a callable with the signature C{(success, result)}. + If the callable returns normally, C{onResult} is called with + C{(True, result)} where C{result} is the return value of the + callable. If the callable throws an exception, C{onResult} is + called with C{(False, failure)}. - Optionally, onResult may be None, in which case it is not + Optionally, C{onResult} may be C{None}, in which case it is not called at all. @param func: callable object to be called in separate thread - @param *args: positional arguments to be passed to func + @param *args: positional arguments to be passed to C{func} - @param **kwargs: keyword arguments to be passed to func + @param **kwargs: keyword arguments to be passed to C{func} """ if self.joined: return @@ -164,35 +150,9 @@ self._startSomeWorkers() - def _runWithCallback(self, callback, errback, func, args, kwargs): - try: - result = apply(func, args, kwargs) - except: - errback(sys.exc_info()[1]) - else: - callback(result) - - - def dispatchWithCallback(self, owner, callback, errback, func, *args, **kw): - """ - DEPRECATED: use L{twisted.internet.threads.deferToThread} instead. - - Dispatch a function, returning the result to a callback function. - - The callback function will be called in the thread - make sure it is - thread-safe. - """ - warnings.warn("dispatchWithCallback() is deprecated since Twisted 8.0, " - "use twisted.internet.threads.deferToThread() instead.", - DeprecationWarning, stacklevel=2) - self.callInThread( - self._runWithCallback, callback, errback, func, args, kw - ) - - def _worker(self): """ - Method used as target of the created threads: retrieve task to run + Method used as target of the created threads: retrieve a task to run from the threadpool, run it, and proceed to the next task until threadpool is stopped. """ @@ -232,6 +192,7 @@ self.threads.remove(ct) + def stop(self): """ Shutdown the threads in the threadpool. @@ -247,6 +208,7 @@ for thread in threads: thread.join() + def adjustPoolsize(self, minthreads=None, maxthreads=None): if minthreads is None: minthreads = self.min @@ -270,44 +232,9 @@ # Start some threads if there is a need. self._startSomeWorkers() + def dumpStats(self): log.msg('queue: %s' % self.q.queue) log.msg('waiters: %s' % self.waiters) log.msg('workers: %s' % self.working) log.msg('total: %s' % self.threads) - - - -class ThreadSafeList: - """ - In Jython 2.1 lists aren't thread-safe, so this wraps it. Newer versions - of Jython are completely different than 2.1, so this class is deprecated - to make way for future versions of Jython. - """ - - deprecatedModuleAttribute( - Version("Twisted", 10, 1, 0), - "This was an internal implementation detail of support for Jython 2.1," - " which is now obsolete.", - __name__, "ThreadSafeList") - - def __init__(self): - self.lock = threading.Lock() - self.l = [] - - def append(self, i): - self.lock.acquire() - try: - self.l.append(i) - finally: - self.lock.release() - - def remove(self, i): - self.lock.acquire() - try: - self.l.remove(i) - finally: - self.lock.release() - - def __len__(self): - return len(self.l) diff -Nru twisted-12.0.0/twisted/python/util.py twisted-12.2.0/twisted/python/util.py --- twisted-12.0.0/twisted/python/util.py 2011-03-27 01:37:18.000000000 +0000 +++ twisted-12.2.0/twisted/python/util.py 2012-06-19 17:27:25.000000000 +0000 @@ -2,7 +2,7 @@ # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. -import os, sys, hmac, errno, inspect, warnings +import os, sys, errno, inspect, warnings import types try: import pwd, grp @@ -59,7 +59,8 @@ def has_key(self, key): """Case insensitive test whether 'key' exists.""" k = self._lowerOrReturn(key) - return self.data.has_key(k) + return k in self.data + __contains__=has_key def _doPreserve(self, key): @@ -210,12 +211,14 @@ dct = {} result = [] for k in lst: - if not dct.has_key(k): result.append(k) + if k not in dct: + result.append(k) dct[k] = 1 return result def padTo(n, seq, default=None): - """Pads a sequence out to n elements, + """ + Pads a sequence out to n elements, filling in with a default value if it is not long enough. @@ -235,7 +238,11 @@ return blank + def getPluginDirs(): + warnings.warn( + "twisted.python.util.getPluginDirs is deprecated since Twisted 12.2.", + DeprecationWarning, stacklevel=2) import twisted systemPlugins = os.path.join(os.path.dirname(os.path.dirname( os.path.abspath(twisted.__file__))), 'plugins') @@ -244,13 +251,19 @@ allPlugins = filter(os.path.isdir, [systemPlugins, userPlugins, confPlugins]) return allPlugins + def addPluginDir(): + warnings.warn( + "twisted.python.util.addPluginDir is deprecated since Twisted 12.2.", + DeprecationWarning, stacklevel=2) sys.path.extend(getPluginDirs()) + def sibpath(path, sibling): - """Return the path to a sibling of a file in the filesystem. + """ + Return the path to a sibling of a file in the filesystem. - This is useful in conjunction with the special __file__ attribute + This is useful in conjunction with the special C{__file__} attribute that Python provides for modules, so modules can load associated resource files. """ @@ -258,7 +271,9 @@ def _getpass(prompt): - """Helper to turn IOErrors into KeyboardInterrupts""" + """ + Helper to turn IOErrors into KeyboardInterrupts. + """ import getpass try: return getpass.getpass(prompt) @@ -317,11 +332,6 @@ sys.stdin, sys.stdout = old -def dict(*a, **k): - import __builtin__ - warnings.warn('twisted.python.util.dict is deprecated. Use __builtin__.dict instead') - return __builtin__.dict(*a, **k) - def println(*a): sys.stdout.write(' '.join(map(str, a))+'\n') @@ -332,18 +342,10 @@ def str_xor(s, b): return ''.join([chr(ord(c) ^ b) for c in s]) -def keyed_md5(secret, challenge): - """ - Create the keyed MD5 string for the given secret and challenge. - """ - warnings.warn( - "keyed_md5() is deprecated. Use the stdlib module hmac instead.", - DeprecationWarning, stacklevel=2 - ) - return hmac.HMAC(secret, challenge).hexdigest() def makeStatBar(width, maxPosition, doneChar = '=', undoneChar = '-', currentChar = '>'): - """Creates a function that will return a string representing a progress bar. + """ + Creates a function that will return a string representing a progress bar. """ aValue = width / float(maxPosition) def statBar(position, force = 0, last = ['']): @@ -368,8 +370,11 @@ """ % (doneChar * 3, currentChar, undoneChar * 3, width, maxPosition, currentChar) return statBar + def spewer(frame, s, ignored): - """A trace function for sys.settrace that prints every function or method call.""" + """ + A trace function for sys.settrace that prints every function or method call. + """ from twisted.python import reflect if frame.f_locals.has_key('self'): se = frame.f_locals['self'] @@ -386,8 +391,10 @@ frame.f_code.co_filename, frame.f_lineno) + def searchupwards(start, files=[], dirs=[]): - """Walk upwards from start, looking for a directory containing + """ + Walk upwards from start, looking for a directory containing all files and directories given as arguments:: >>> searchupwards('.', ['foo.txt'], ['bar', 'bam']) @@ -447,18 +454,22 @@ """Empty the log""" self.log = [None]*self.size + def raises(exception, f, *args, **kwargs): - """Determine whether the given call raises the given exception""" + """ + Determine whether the given call raises the given exception. + """ try: f(*args, **kwargs) except exception: return 1 return 0 + class IntervalDifferential: """ Given a list of intervals, generate the amount of time to sleep between - \"instants\". + "instants". For example, given 7, 11 and 13, the three (infinite) sequences:: @@ -489,6 +500,7 @@ def __iter__(self): return _IntervalDifferentialIterator(self.intervals, self.default) + class _IntervalDifferentialIterator: def __init__(self, i, d): @@ -529,7 +541,7 @@ class FancyStrMixin: """ Set showAttributes to a sequence of strings naming attributes, OR - sequences of (attributeName, displayName, formatCharacter) + sequences of C{(attributeName, displayName, formatCharacter)}. """ showAttributes = () def __str__(self): @@ -565,19 +577,6 @@ -def dsu(list, key): - """ - decorate-sort-undecorate (aka "Schwartzian transform") - - DEPRECATED. Use the built-in C{sorted()} instead. - """ - warnings.warn(("dsu is deprecated since Twisted 10.1. " - "Use the built-in sorted() instead."), DeprecationWarning, stacklevel=2) - L2 = [(key(e), i, e) for (i, e) in zip(range(len(list)), list)] - L2.sort() - return [e[2] for e in L2] - - try: from twisted.python._initgroups import initgroups as _c_initgroups except ImportError: @@ -718,7 +717,9 @@ class SubclassableCStringIO(object): - """A wrapper around cStringIO to allow for subclassing""" + """ + A wrapper around cStringIO to allow for subclassing. + """ __csio = None def __init__(self, *a, **kw): @@ -767,15 +768,6 @@ def getvalue(self): return self.__csio.getvalue() -def moduleMovedForSplit(origModuleName, newModuleName, moduleDesc, - projectName, projectURL, globDict): - """ - No-op function; only present for backwards compatibility. There is no - reason to call this function. - """ - warnings.warn( - "moduleMovedForSplit is deprecated since Twisted 9.0.", - DeprecationWarning, stacklevel=2) def untilConcludes(f, *a, **kw): @@ -998,10 +990,9 @@ __all__ = [ "uniquify", "padTo", "getPluginDirs", "addPluginDir", "sibpath", - "getPassword", "dict", "println", "keyed_md5", "makeStatBar", - "OrderedDict", "InsensitiveDict", "spewer", "searchupwards", "LineLog", + "getPassword", "println", "makeStatBar", "OrderedDict", + "InsensitiveDict", "spewer", "searchupwards", "LineLog", "raises", "IntervalDifferential", "FancyStrMixin", "FancyEqMixin", - "dsu", "switchUID", "SubclassableCStringIO", "moduleMovedForSplit", - "unsignedID", "mergeFunctionMetadata", "nameToLabel", "uidFromString", - "gidFromString", "runAsEffectiveUser", "moduleMovedForSplit", + "switchUID", "SubclassableCStringIO", "unsignedID", "mergeFunctionMetadata", + "nameToLabel", "uidFromString", "gidFromString", "runAsEffectiveUser", ] diff -Nru twisted-12.0.0/twisted/python/win32.py twisted-12.2.0/twisted/python/win32.py --- twisted-12.0.0/twisted/python/win32.py 2011-11-07 04:58:37.000000000 +0000 +++ twisted-12.2.0/twisted/python/win32.py 2012-07-28 14:23:55.000000000 +0000 @@ -12,7 +12,6 @@ """ import re -import exceptions import os try: @@ -31,19 +30,16 @@ O_BINARY = getattr(os, "O_BINARY", 0) -def _determineWindowsError(): - """ - Determine which WindowsError name to export. - """ - return getattr(exceptions, 'WindowsError', FakeWindowsError) - class FakeWindowsError(OSError): """ Stand-in for sometimes-builtin exception on platforms for which it is missing. """ -WindowsError = _determineWindowsError() +try: + WindowsError = WindowsError +except NameError: + WindowsError = FakeWindowsError # XXX fix this to use python's builtin _winreg? diff -Nru twisted-12.0.0/twisted/python/zippath.py twisted-12.2.0/twisted/python/zippath.py --- twisted-12.0.0/twisted/python/zippath.py 2011-03-14 21:00:23.000000000 +0000 +++ twisted-12.2.0/twisted/python/zippath.py 2012-03-13 23:29:48.000000000 +0000 @@ -3,9 +3,7 @@ # See LICENSE for details. """ -This module contains partial re-implementations of FilePath, pending some -specification of formal interfaces it is a duck-typing attempt to emulate them -for certain restricted uses. +This module contains implementations of IFilePath for zip files. See the constructor for ZipArchive for use. """ @@ -27,7 +25,9 @@ _USE_ZIPFILE = False from twisted.python.zipstream import ChunkingZipFile -from twisted.python.filepath import FilePath, _PathHelper +from twisted.python.filepath import IFilePath, FilePath, AbstractFilePath + +from zope.interface import implements # using FilePath here exclusively rather than os to make sure that we don't do # anything OS-path-specific here. @@ -36,10 +36,15 @@ # path separator, regardless of platform. -class ZipPath(_PathHelper): +class ZipPath(AbstractFilePath): """ I represent a file or directory contained within a zip file. """ + + implements(IFilePath) + + sep = ZIP_PATH_SEP + def __init__(self, archive, pathInArchive): """ Don't construct me directly. Use ZipArchive.child(). @@ -136,15 +141,25 @@ # less meaningful here. return self.parent().path - def open(self): + def open(self, mode="r"): if _USE_ZIPFILE: - return self.archive.zipfile.open(self.pathInArchive) + return self.archive.zipfile.open(self.pathInArchive, mode=mode) else: + # XXX oh man, is this too much hax? + self.archive.zipfile.mode = mode return self.archive.zipfile.readfile(self.pathInArchive) - def restat(self): + def changed(self): pass + def getsize(self): + """ + Retrieve this file's size. + + @return: file size, in bytes + """ + + return self.archive.zipfile.NameToInfo[self.pathInArchive].file_size def getAccessTime(self): """ diff -Nru twisted-12.0.0/twisted/python/zipstream.py twisted-12.2.0/twisted/python/zipstream.py --- twisted-12.0.0/twisted/python/zipstream.py 2011-03-25 23:35:57.000000000 +0000 +++ twisted-12.2.0/twisted/python/zipstream.py 2012-08-08 20:17:02.000000000 +0000 @@ -7,18 +7,18 @@ bit of a file at a time, which means you can report progress as a file unzips. """ -import warnings import zipfile import os.path import zlib import struct + _fileHeaderSize = struct.calcsize(zipfile.structFileHeader) class ChunkingZipFile(zipfile.ZipFile): """ - A ZipFile object which, with readfile(), also gives you access to a - filelike object for each entry. + A C{ZipFile} object which, with L{readfile}, also gives you access to a + file-like object for each entry. """ def readfile(self, name): @@ -77,11 +77,11 @@ @ivar closed: File-like 'closed' attribute; True before this file has been closed, False after. - @type closed: L{bool} + @type closed: C{bool} @ivar finished: An older, broken synonym for 'closed'. Do not touch this, please. - @type finished: L{int} + @type finished: C{int} """ def __init__(self, chunkingZipFile, length): """ @@ -238,64 +238,8 @@ -def unzip(filename, directory=".", overwrite=0): - """ - Unzip the file - - @param filename: the name of the zip file - @param directory: the directory into which the files will be - extracted - @param overwrite: if on, overwrite files when they exist. You can - still get an error if you try to create a directory over a file - with the same name or vice-versa. - """ - warnings.warn("zipstream.unzip is deprecated since Twisted 11.0.0 for " + - "security reasons. Use Python's zipfile instead.", - category=DeprecationWarning, stacklevel=2) - - for i in unzipIter(filename, directory, overwrite, suppressWarning=True): - pass - DIR_BIT = 16 -def unzipIter(filename, directory='.', overwrite=0, suppressWarning=False): - """ - Return a generator for the zipfile. This implementation will yield - after every file. - - The value it yields is the number of files left to unzip. - """ - if not suppressWarning: - warnings.warn("zipstream.unzipIter is deprecated since Twisted " + - "11.0.0 for security reasons. Use Python's " + - "zipfile instead.", - category=DeprecationWarning, stacklevel=2) - - zf = zipfile.ZipFile(filename, 'r') - names = zf.namelist() - if not os.path.exists(directory): - os.makedirs(directory) - remaining = len(zf.namelist()) - for entry in names: - remaining -= 1 - isdir = zf.getinfo(entry).external_attr & DIR_BIT - f = os.path.join(directory, entry) - if isdir: - # overwrite flag only applies to files - if not os.path.exists(f): - os.makedirs(f) - else: - # create the directory the file will be in first, - # since we can't guarantee it exists - fdir = os.path.split(f)[0] - if not os.path.exists(fdir): - os.makedirs(fdir) - if overwrite or not os.path.exists(f): - outfile = file(f, 'wb') - outfile.write(zf.read(entry)) - outfile.close() - yield remaining - def countZipFileChunks(filename, chunksize): """ @@ -311,14 +255,14 @@ def countFileChunks(zipinfo, chunksize): """ - Count the number of chunks that will result from the given L{ZipInfo}. + Count the number of chunks that will result from the given C{ZipInfo}. - @param zipinfo: a L{zipfile.ZipInfo} instance describing an entry in a zip + @param zipinfo: a C{zipfile.ZipInfo} instance describing an entry in a zip archive to be counted. @return: the number of chunks present in the zip file. (Even an empty file counts as one chunk.) - @rtype: L{int} + @rtype: C{int} """ count, extra = divmod(zipinfo.file_size, chunksize) if extra > 0: @@ -326,18 +270,6 @@ return count or 1 -def countZipFileEntries(filename): - """ - Count the number of entries in a zip archive. (Don't use this function.) - - @param filename: The filename of a zip archive. - @type filename: L{str} - """ - warnings.warn("countZipFileEntries is deprecated.", - DeprecationWarning, 2) - zf = zipfile.ZipFile(filename) - return len(zf.namelist()) - def unzipIterChunky(filename, directory='.', overwrite=0, chunksize=4096): diff -Nru twisted-12.0.0/twisted/scripts/__init__.py twisted-12.2.0/twisted/scripts/__init__.py --- twisted-12.0.0/twisted/scripts/__init__.py 2011-10-12 12:08:56.000000000 +0000 +++ twisted-12.2.0/twisted/scripts/__init__.py 2012-02-19 20:39:01.000000000 +0000 @@ -11,10 +11,17 @@ from twisted.python.versions import Version from twisted.python.deprecate import deprecatedModuleAttribute + deprecatedModuleAttribute( Version("Twisted", 11, 1, 0), "Seek unzipping software outside of Twisted.", __name__, "tkunzip") +deprecatedModuleAttribute( + Version("Twisted", 12, 1, 0), + "tapconvert has been deprecated.", + __name__, + "tapconvert") + del Version, deprecatedModuleAttribute diff -Nru twisted-12.0.0/twisted/scripts/_twistd_unix.py twisted-12.2.0/twisted/scripts/_twistd_unix.py --- twisted-12.0.0/twisted/scripts/_twistd_unix.py 2011-10-18 10:31:11.000000000 +0000 +++ twisted-12.2.0/twisted/scripts/_twistd_unix.py 2012-01-23 22:55:41.000000000 +0000 @@ -7,6 +7,7 @@ from twisted.python import log, syslog, logfile, usage from twisted.python.util import switchUID, uidFromString, gidFromString from twisted.application import app, service +from twisted.internet.interfaces import IReactorDaemonize from twisted import copyright @@ -155,8 +156,26 @@ -def daemonize(): - # See http://www.erlenstar.demon.co.uk/unix/faq_toc.html#TOC16 +def daemonize(reactor, os): + """ + Daemonizes the application on Unix. This is done by the usual double + forking approach. + + @see: U{http://code.activestate.com/recipes/278731/} + @see: W. Richard Stevens, "Advanced Programming in the Unix Environment", + 1992, Addison-Wesley, ISBN 0-201-56317-7 + + @param reactor: The reactor in use. If it provides L{IReactorDaemonize}, + its daemonization-related callbacks will be invoked. + + @param os: An object like the os module to use to perform the daemonization. + """ + + ## If the reactor requires hooks to be called for daemonization, call them. + ## Currently the only reactor which provides/needs that is KQueueReactor. + if IReactorDaemonize.providedBy(reactor): + reactor.beforeDaemonize() + if os.fork(): # launch child and... os._exit(0) # kill off parent os.setsid() @@ -171,6 +190,9 @@ raise os.close(null) + if IReactorDaemonize.providedBy(reactor): + reactor.afterDaemonize() + def launchWithName(name): @@ -265,7 +287,8 @@ if umask is not None: os.umask(umask) if daemon: - daemonize() + from twisted.internet import reactor + daemonize(reactor, os) if pidfile: f = open(pidfile,'wb') f.write(str(os.getpid())) diff -Nru twisted-12.0.0/twisted/scripts/tap2rpm.py twisted-12.2.0/twisted/scripts/tap2rpm.py --- twisted-12.0.0/twisted/scripts/tap2rpm.py 2011-10-18 10:31:11.000000000 +0000 +++ twisted-12.2.0/twisted/scripts/tap2rpm.py 2012-03-13 21:08:17.000000000 +0000 @@ -7,8 +7,9 @@ import tempfile import tarfile from StringIO import StringIO +import warnings -from twisted.python import usage, log +from twisted.python import usage, log, versions, deprecate ################################# @@ -36,48 +37,48 @@ # check for required files if [ ! -x /usr/bin/twistd ] then - echo "$0: Aborting, no /usr/bin/twistd found" - exit 0 + echo "$0: Aborting, no /usr/bin/twistd found" + exit 0 fi if [ ! -r "$file" ] then - echo "$0: Aborting, no file $file found." - exit 0 + echo "$0: Aborting, no file $file found." + exit 0 fi # set up run directory if necessary if [ ! -d "${rundir}" ] then - mkdir -p "${rundir}" + mkdir -p "${rundir}" fi case "$1" in - start) - echo -n "Starting %(rpm_file)s: twistd" - daemon twistd \\ - --pidfile=$pidfile \\ - --rundir=$rundir \\ - --%(twistd_option)s=$file \\ - --logfile=$logfile - status %(rpm_file)s - ;; - - stop) - echo -n "Stopping %(rpm_file)s: twistd" - kill `cat "${pidfile}"` - status %(rpm_file)s - ;; - - restart) - "${0}" stop - "${0}" start - ;; + start) + echo -n "Starting %(rpm_file)s: twistd" + daemon twistd \\ + --pidfile=$pidfile \\ + --rundir=$rundir \\ + --%(twistd_option)s=$file \\ + --logfile=$logfile + status %(rpm_file)s + ;; + + stop) + echo -n "Stopping %(rpm_file)s: twistd" + kill `cat "${pidfile}"` + status %(rpm_file)s + ;; + + restart) + "${0}" stop + "${0}" start + ;; *) - echo "Usage: ${0} {start|stop|restart|}" >&2 - exit 1 - ;; + echo "Usage: ${0} {start|stop|restart|}" >&2 + exit 1 + ;; esac exit 0 @@ -106,7 +107,7 @@ %%install [ ! -z "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] \ - && rm -rf "$RPM_BUILD_ROOT" + && rm -rf "$RPM_BUILD_ROOT" mkdir -p "$RPM_BUILD_ROOT"/etc/twisted-taps mkdir -p "$RPM_BUILD_ROOT"/etc/init.d mkdir -p "$RPM_BUILD_ROOT"/var/lib/twisted-taps @@ -115,7 +116,7 @@ %%clean [ ! -z "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != '/' ] \ - && rm -rf "$RPM_BUILD_ROOT" + && rm -rf "$RPM_BUILD_ROOT" %%post /sbin/chkconfig --add %(rpm_file)s @@ -138,7 +139,7 @@ ############################### class MyOptions(usage.Options): - optFlags = [["unsigned", "u"], ['quiet', 'q']] + optFlags = [['quiet', 'q']] optParameters = [ ["tapfile", "t", "twistd.tap"], ["maintainer", "m", "tap2rpm"], @@ -177,6 +178,18 @@ self['release-name'] = '%s-%s' % (self['rpmfile'], self['set-version']) + def opt_unsigned(self): + """ + Generate an unsigned rather than a signed RPM. (DEPRECATED; unsigned + is the default) + """ + msg = deprecate.getDeprecationWarningString( + self.opt_unsigned, versions.Version("Twisted", 12, 1, 0)) + warnings.warn(msg, category=DeprecationWarning, stacklevel=2) + + # Maintain the -u short flag + opt_u = opt_unsigned + type_dict = { 'tap': 'file', diff -Nru twisted-12.0.0/twisted/scripts/tapconvert.py twisted-12.2.0/twisted/scripts/tapconvert.py --- twisted-12.0.0/twisted/scripts/tapconvert.py 2011-10-18 10:31:11.000000000 +0000 +++ twisted-12.2.0/twisted/scripts/tapconvert.py 2012-02-19 20:39:01.000000000 +0000 @@ -1,10 +1,12 @@ # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +import sys, getpass + from twisted.python import usage from twisted.application import app from twisted.persisted import sob -import sys, getpass + class ConvertOptions(usage.Options): synopsis = "Usage: tapconvert [options]" diff -Nru twisted-12.0.0/twisted/scripts/test/test_scripts.py twisted-12.2.0/twisted/scripts/test/test_scripts.py --- twisted-12.0.0/twisted/scripts/test/test_scripts.py 2011-10-21 13:15:37.000000000 +0000 +++ twisted-12.2.0/twisted/scripts/test/test_scripts.py 2012-02-19 20:39:01.000000000 +0000 @@ -147,6 +147,21 @@ self.assertEqual(1, len(warnings)) + def test_deprecatedTapconvert(self): + """ + The entire L{twisted.scripts.tapconvert} module is deprecated. + """ + from twisted.scripts import tapconvert + warnings = self.flushWarnings( + offendingFunctions=[self.test_deprecatedTapconvert]) + self.assertEqual(DeprecationWarning, warnings[0]['category']) + self.assertEqual( + "twisted.scripts.tapconvert was deprecated in Twisted 12.1.0: " + "tapconvert has been deprecated.", + warnings[0]['message']) + self.assertEqual(1, len(warnings)) + + class ZshIntegrationTestCase(TestCase, ZshScriptTestMixin): """ diff -Nru twisted-12.0.0/twisted/scripts/test/test_tap2rpm.py twisted-12.2.0/twisted/scripts/test/test_tap2rpm.py --- twisted-12.0.0/twisted/scripts/test/test_tap2rpm.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/scripts/test/test_tap2rpm.py 2012-03-13 21:08:17.000000000 +0000 @@ -5,8 +5,11 @@ Tests for L{twisted.scripts.tap2rpm}. """ import os + from twisted.trial.unittest import TestCase, SkipTest from twisted.python import procutils +from twisted.python import versions +from twisted.python import deprecate from twisted.python.failure import Failure from twisted.internet import utils from twisted.scripts import tap2rpm @@ -378,3 +381,19 @@ # Try and make an RPM from that tapfile. _makeRPMs(tapfile=tapfile) + + + def test_unsignedFlagDeprecationWarning(self): + """ + The 'unsigned' flag in tap2rpm should be deprecated, and its use + should raise a warning as such. + """ + config = tap2rpm.MyOptions() + config.parseOptions(['--unsigned']) + warnings = self.flushWarnings() + self.assertEqual(DeprecationWarning, warnings[0]['category']) + self.assertEqual( + deprecate.getDeprecationWarningString( + config.opt_unsigned, versions.Version("Twisted", 12, 1, 0)), + warnings[0]['message']) + self.assertEqual(1, len(warnings)) diff -Nru twisted-12.0.0/twisted/scripts/tkunzip.py twisted-12.2.0/twisted/scripts/tkunzip.py --- twisted-12.0.0/twisted/scripts/tkunzip.py 2011-10-12 12:08:56.000000000 +0000 +++ twisted-12.2.0/twisted/scripts/tkunzip.py 2012-05-31 17:58:56.000000000 +0000 @@ -3,11 +3,9 @@ # See LICENSE for details. """ -Post-install GUI to compile to pyc and unpack twisted doco +Post-install GUI to compile to pyc and unpack twisted doco. """ -from __future__ import generators - import sys import zipfile import py_compile @@ -15,7 +13,7 @@ # we're going to ignore failures to import tkinter and fall back # to using the console if the required dll is not found -# Scary kludge to work around tk84.dll bug: +# Scary kludge to work around tk84.dll bug: # https://sourceforge.net/tracker/index.php?func=detail&aid=814654&group_id=5470&atid=105470 # Without which(): you get a windows missing-dll popup message from twisted.python.procutils import which @@ -71,7 +69,7 @@ def pack(self, *args, **kwargs): self.frame.pack(*args, **kwargs) - + def updateProgress(self, newValue, newMax=None): if newMax: self.max = newMax @@ -91,7 +89,7 @@ float(value) / self.max * self.width, self.height) else: self.canvas.coords(self.scale, 0, - self.height - (float(value) / + self.height - (float(value) / self.max*self.height), self.width, self.height) # Now update the colors @@ -101,7 +99,7 @@ if self.doLabel: if value: if value >= 0: - pvalue = int((float(value) / float(self.max)) * + pvalue = int((float(value) / float(self.max)) * 100.0) else: pvalue = 0 @@ -133,7 +131,7 @@ def setIterator(self, iterator): self.iterator=iterator return self - + def updateBar(self, deferred): b=self.bar try: @@ -156,14 +154,14 @@ if self.stopping: deferred.callback(self.root) return - + try: self.remaining=self.iterator.next() except StopIteration: - self.stopping=1 + self.stopping=1 except: deferred.errback(failure.Failure()) - + if self.remaining%10==0: reactor.callLater(0, self.updateBar, deferred) if self.remaining%100==0: @@ -218,7 +216,7 @@ if opt['use-console']: # this should come before shell-exec to prevent infinite loop - return doItConsolicious(opt) + return doItConsolicious(opt) if opt['shell-exec'] or not 'Tkinter' in sys.modules: from distutils import sysconfig from twisted.scripts import tkunzip @@ -240,7 +238,7 @@ if n % 1000 == 0: print print 'Done unpacking.' - + if opt['compiledir']: print 'Compiling to pyc...' import compileall @@ -253,7 +251,7 @@ root.title('One Moment.') root.protocol('WM_DELETE_WINDOW', reactor.stop) tksupport.install(root) - + prog=ProgressBar(root, value=0, labelColor="black", width=200) prog.pack() @@ -265,7 +263,7 @@ return root d.addCallback(deiconify) - + if opt['zipfile']: uz=Progressor('Unpacking documentation...') max=zipstream.countZipFileChunks(opt['zipfile'], 4096) diff -Nru twisted-12.0.0/twisted/scripts/trial.py twisted-12.2.0/twisted/scripts/trial.py --- twisted-12.0.0/twisted/scripts/trial.py 2011-10-18 10:31:11.000000000 +0000 +++ twisted-12.2.0/twisted/scripts/trial.py 2012-08-03 11:10:08.000000000 +0000 @@ -8,7 +8,7 @@ from twisted.internet import defer from twisted.application import app -from twisted.python import usage, reflect, failure, versions, deprecate +from twisted.python import usage, reflect, failure from twisted.python.filepath import FilePath from twisted import plugin from twisted.python.util import spewer @@ -142,7 +142,6 @@ ) fallbackReporter = reporter.TreeReporter - extra = None tracer = None def __init__(self): @@ -163,8 +162,8 @@ def opt_coverage(self): """ - Generate coverage information in the I{coverage} file in the - directory specified by the I{trial-temp} option. + Generate coverage information in the coverage file in the + directory specified by the temp-directory option. """ import trace self.tracer = trace.Trace(count=1, trace=0) @@ -234,21 +233,6 @@ "tbformat must be 'plain', 'emacs', or 'cgitb'.") - def opt_extra(self, arg): - """ - Add an extra argument. (This is a hack necessary for interfacing with - emacs's `gud'.) NOTE: This option is deprecated as of Twisted 11.0 - """ - warnings.warn(deprecate.getDeprecationWarningString(Options.opt_extra, - versions.Version('Twisted', 11, 0, 0)), - category=DeprecationWarning, stacklevel=2) - - if self.extra is None: - self.extra = [] - self.extra.append(arg) - opt_x = opt_extra - - def opt_recursionlimit(self, arg): """ see sys.setrecursionlimit() @@ -288,8 +272,6 @@ def parseArgs(self, *args): self['tests'].update(args) - if self.extra is not None: - self['tests'].update(self.extra) def _loadReporterByName(self, name): diff -Nru twisted-12.0.0/twisted/spread/flavors.py twisted-12.2.0/twisted/spread/flavors.py --- twisted-12.0.0/twisted/spread/flavors.py 2011-06-24 01:57:16.000000000 +0000 +++ twisted-12.2.0/twisted/spread/flavors.py 2012-06-12 13:20:20.000000000 +0000 @@ -210,7 +210,7 @@ kw = broker.unserialize(kw, self.perspective) method = getattr(self.object, "view_%s" % message) try: - state = apply(method, (self.perspective,)+args, kw) + state = method(*(self.perspective,)+args, **kw) except TypeError: log.msg("%s didn't accept %s and %s" % (method, args, kw)) raise @@ -417,7 +417,7 @@ kw = broker.unserialize(kw) method = getattr(self, "observe_%s" % message) try: - state = apply(method, args, kw) + state = method(*args, **kw) except TypeError: log.msg("%s didn't accept %s and %s" % (method, args, kw)) raise diff -Nru twisted-12.0.0/twisted/spread/pb.py twisted-12.2.0/twisted/spread/pb.py --- twisted-12.0.0/twisted/spread/pb.py 2011-11-14 18:11:49.000000000 +0000 +++ twisted-12.2.0/twisted/spread/pb.py 2012-06-07 13:15:27.000000000 +0000 @@ -844,13 +844,13 @@ pbc = None pbe = None answerRequired = 1 - if kw.has_key('pbcallback'): + if 'pbcallback' in kw: pbc = kw['pbcallback'] del kw['pbcallback'] - if kw.has_key('pberrback'): + if 'pberrback' in kw: pbe = kw['pberrback'] del kw['pberrback'] - if kw.has_key('pbanswer'): + if 'pbanswer' in kw: assert (not pbe) and (not pbc), "You can't specify a no-answer requirement." answerRequired = kw['pbanswer'] del kw['pbanswer'] diff -Nru twisted-12.0.0/twisted/spread/refpath.py twisted-12.2.0/twisted/spread/refpath.py --- twisted-12.0.0/twisted/spread/refpath.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/spread/refpath.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,95 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Path-based references for PB, and other reference-based protocols. - -Maintainer: Glyph Lefkowitz -""" - - -from copy import copy -import os, warnings - -from twisted.python import log -from twisted.spread.flavors import Referenceable, Viewable - -warnings.warn( - "twisted.spread.refpath is deprecated since Twisted 9.0.", - category=DeprecationWarning, stacklevel=2) - -### "Server"-side objects - -class PathReferenceContext: - def __init__(self, path, root): - self.metadata = {} - self.path = path - self.root = root - - def __setitem__(self, key, item): - self.metadata[key] = item - - def __getitem__(self, key): - return self.metadata[key] - - def getObject(self): - o = self.root - for p in self.path: - o = o.getChild(p, self) - return o - -class PathReference: - def __init__(self): - self.children = {} - def getChild(self, child, ctx): - return self.children[child] - -class PathReferenceDirectory(Referenceable): - def __init__(self, root, prefix="remote"): - self.root = root - self.prefix = prefix - def remote_callPath(self, path, name, *args, **kw): - ctx = PathReferenceContext(path, self) - obj = ctx.getObject() - return apply(getattr(obj, "%s_%s" % (self.prefix, name)), args, kw) - -class PathReferenceContextDirectory(Referenceable): - def __init__(self, root, prefix="remote"): - self.root = root - self.prefix = prefix - def remote_callPath(self, path, name, *args, **kw): - ctx = PathReferenceContext(path, self) - obj = ctx.getObject() - return apply(getattr(obj, "%s_%s" % (self.prefix, name)), - (ctx,)+args, kw) - -class PathViewDirectory(Viewable): - def __init__(self, root, prefix="view"): - self.root = root - self.prefix = prefix - def view_callPath(self, perspective, path, name, *args, **kw): - ctx = PathReferenceContext(path, self) - obj = ctx.getObject() - return apply(getattr(obj, "%s_%s" % (self.prefix, name)), - (perspective,)+args, kw) - -class PathViewContextDirectory(Viewable): - def __init__(self, root, prefix="view"): - self.root = root - self.prefix = prefix - def view_callPath(self, perspective, path, name, *args, **kw): - ctx = PathReferenceContext(path, self) - obj = ctx.getObject() - return apply(getattr(obj, "%s_%s" % (self.prefix, name)), - (perspective,ctx)+args, kw) - -### "Client"-side objects - -class RemotePathReference: - def __init__(self, ref, path): - self.ref = ref - self.path = path - - def callRemote(self, name, *args, **kw): - apply(self.ref.callRemote, - ("callPath", self.path, name)+args, kw) diff -Nru twisted-12.0.0/twisted/spread/ui/gtk2util.py twisted-12.2.0/twisted/spread/ui/gtk2util.py --- twisted-12.0.0/twisted/spread/ui/gtk2util.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/spread/ui/gtk2util.py 2012-05-31 17:58:56.000000000 +0000 @@ -1,10 +1,6 @@ - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -from __future__ import nested_scopes - import gtk from twisted import copyright diff -Nru twisted-12.0.0/twisted/test/_preamble.py twisted-12.2.0/twisted/test/_preamble.py --- twisted-12.0.0/twisted/test/_preamble.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/test/_preamble.py 2012-01-23 22:55:41.000000000 +0000 @@ -0,0 +1,17 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +# This makes sure Twisted-using child processes used in the test suite import +# the correct version of Twisted (ie, the version of Twisted under test). + +# This is a copy of the bin/_preamble.py script because it's not clear how to +# use the functionality for both things without having a copy. + +import sys, os + +path = os.path.abspath(sys.argv[0]) +while os.path.dirname(path) != path: + if os.path.exists(os.path.join(path, 'twisted', '__init__.py')): + sys.path.insert(0, path) + break + path = os.path.dirname(path) diff -Nru twisted-12.0.0/twisted/test/generator_failure_tests.py twisted-12.2.0/twisted/test/generator_failure_tests.py --- twisted-12.0.0/twisted/test/generator_failure_tests.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/generator_failure_tests.py 2012-06-07 14:09:07.000000000 +0000 @@ -4,6 +4,7 @@ """ Python 2.5+ test cases for failures thrown into generators. """ +from __future__ import division import sys import traceback diff -Nru twisted-12.0.0/twisted/test/proto_helpers.py twisted-12.2.0/twisted/test/proto_helpers.py --- twisted-12.0.0/twisted/test/proto_helpers.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/proto_helpers.py 2012-08-04 11:59:34.000000000 +0000 @@ -6,18 +6,22 @@ Assorted functionality which is commonly useful when writing unit tests. """ +from socket import AF_INET, AF_INET6 from StringIO import StringIO from zope.interface import implements -from twisted.internet.interfaces import ITransport, IConsumer, IPushProducer,\ - IConnector -from twisted.internet.interfaces import IReactorTCP, IReactorSSL, IReactorUNIX +from twisted.internet.interfaces import ( + ITransport, IConsumer, IPushProducer, IConnector) +from twisted.internet.interfaces import ( + IReactorTCP, IReactorSSL, IReactorUNIX, IReactorSocket) from twisted.internet.interfaces import IListeningPort +from twisted.internet.abstract import isIPv6Address +from twisted.internet.error import UnsupportedAddressFamily from twisted.protocols import basic from twisted.internet import protocol, error, address -from twisted.internet.address import IPv4Address, UNIXAddress +from twisted.internet.address import IPv4Address, UNIXAddress, IPv6Address class AccumulatingProtocol(protocol.Protocol): @@ -304,7 +308,7 @@ """ A fake L{IConnector} that allows us to inspect if it has been told to stop connecting. - + @ivar stoppedConnecting: has this connector's L{FakeConnector.stopConnecting} method been invoked yet? @@ -380,8 +384,11 @@ @ivar unixServers: a list that keeps track of server listen attempts (ie, calls to C{listenUNIX}). @type unixServers: C{list} + + @ivar adoptedPorts: a list that keeps track of server listen attempts (ie, + calls to C{adoptStreamPort}). """ - implements(IReactorTCP, IReactorSSL, IReactorUNIX) + implements(IReactorTCP, IReactorSSL, IReactorUNIX, IReactorSocket) def __init__(self): """ @@ -393,6 +400,23 @@ self.sslServers = [] self.unixClients = [] self.unixServers = [] + self.adoptedPorts = [] + + + def adoptStreamPort(self, fileno, addressFamily, factory): + """ + Fake L{IReactorSocket.adoptStreamPort}, that logs the call and returns + an L{IListeningPort}. + """ + if addressFamily == AF_INET: + addr = IPv4Address('TCP', '0.0.0.0', 1234) + elif addressFamily == AF_INET6: + addr = IPv6Address('TCP', '::', 1234) + else: + raise UnsupportedAddressFamily() + + self.adoptedPorts.append((fileno, addressFamily, factory)) + return _FakePort(addr) def listenTCP(self, port, factory, backlog=50, interface=''): @@ -401,7 +425,11 @@ L{IListeningPort}. """ self.tcpServers.append((port, factory, backlog, interface)) - return _FakePort(IPv4Address('TCP', '0.0.0.0', port)) + if isIPv6Address(interface): + address = IPv6Address('TCP', interface, port) + else: + address = IPv4Address('TCP', '0.0.0.0', port) + return _FakePort(address) def connectTCP(self, host, port, factory, timeout=30, bindAddress=None): @@ -410,7 +438,12 @@ L{IConnector}. """ self.tcpClients.append((host, port, factory, timeout, bindAddress)) - return _FakeConnector(IPv4Address('TCP', host, port)) + if isIPv6Address(host): + conn = _FakeConnector(IPv6Address('TCP', host, port)) + else: + conn = _FakeConnector(IPv4Address('TCP', host, port)) + factory.startedConnecting(conn) + return conn def listenSSL(self, port, factory, contextFactory, @@ -432,7 +465,9 @@ """ self.sslClients.append((host, port, factory, contextFactory, timeout, bindAddress)) - return _FakeConnector(IPv4Address('TCP', host, port)) + conn = _FakeConnector(IPv4Address('TCP', host, port)) + factory.startedConnecting(conn) + return conn def listenUNIX(self, address, factory, @@ -451,7 +486,9 @@ L{IConnector}. """ self.unixClients.append((address, factory, timeout, checkPID)) - return _FakeConnector(UNIXAddress(address)) + conn = _FakeConnector(UNIXAddress(address)) + factory.startedConnecting(conn) + return conn @@ -463,7 +500,7 @@ @ivar _listenException: An instance of an L{Exception} @ivar _connectException: An instance of an L{Exception} """ - implements(IReactorTCP, IReactorSSL, IReactorUNIX) + implements(IReactorTCP, IReactorSSL, IReactorUNIX, IReactorSocket) def __init__(self, listenException=None, connectException=None): """ @@ -477,6 +514,14 @@ self._connectException = connectException + def adoptStreamPort(self, fileno, addressFamily, factory): + """ + Fake L{IReactorSocket.adoptStreamPort}, that raises + L{self._listenException}. + """ + raise self._listenException + + def listenTCP(self, port, factory, backlog=50, interface=''): """ Fake L{reactor.listenTCP}, that raises L{self._listenException}. diff -Nru twisted-12.0.0/twisted/test/reflect_helper_ZDE.py twisted-12.2.0/twisted/test/reflect_helper_ZDE.py --- twisted-12.0.0/twisted/test/reflect_helper_ZDE.py 2005-02-27 07:19:37.000000000 +0000 +++ twisted-12.2.0/twisted/test/reflect_helper_ZDE.py 2012-06-07 14:09:07.000000000 +0000 @@ -1,4 +1,4 @@ # Helper module for a test_reflect test -1/0 +1//0 diff -Nru twisted-12.0.0/twisted/test/stdio_test_consumer.py twisted-12.2.0/twisted/test/stdio_test_consumer.py --- twisted-12.0.0/twisted/test/stdio_test_consumer.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/stdio_test_consumer.py 2012-01-23 22:55:41.000000000 +0000 @@ -8,7 +8,7 @@ that process transports implement IConsumer properly. """ -import sys +import sys, _preamble from twisted.python import log, reflect from twisted.internet import stdio, protocol diff -Nru twisted-12.0.0/twisted/test/stdio_test_halfclose.py twisted-12.2.0/twisted/test/stdio_test_halfclose.py --- twisted-12.0.0/twisted/test/stdio_test_halfclose.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/stdio_test_halfclose.py 2012-01-23 22:55:41.000000000 +0000 @@ -9,7 +9,7 @@ transports. """ -import sys +import sys, _preamble from zope.interface import implements diff -Nru twisted-12.0.0/twisted/test/stdio_test_hostpeer.py twisted-12.2.0/twisted/test/stdio_test_hostpeer.py --- twisted-12.0.0/twisted/test/stdio_test_hostpeer.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/stdio_test_hostpeer.py 2012-01-23 22:55:41.000000000 +0000 @@ -8,7 +8,7 @@ that ITransport.getHost() and ITransport.getPeer() work for process transports. """ -import sys +import sys, _preamble from twisted.internet import stdio, protocol from twisted.python import reflect diff -Nru twisted-12.0.0/twisted/test/stdio_test_lastwrite.py twisted-12.2.0/twisted/test/stdio_test_lastwrite.py --- twisted-12.0.0/twisted/test/stdio_test_lastwrite.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/stdio_test_lastwrite.py 2012-01-23 22:55:41.000000000 +0000 @@ -9,7 +9,7 @@ L{twisted.internet.stdio.StandardIO} has finished. """ -import sys +import sys, _preamble from twisted.internet.protocol import Protocol from twisted.internet.stdio import StandardIO diff -Nru twisted-12.0.0/twisted/test/stdio_test_loseconn.py twisted-12.2.0/twisted/test/stdio_test_loseconn.py --- twisted-12.0.0/twisted/test/stdio_test_loseconn.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/stdio_test_loseconn.py 2012-01-23 22:55:41.000000000 +0000 @@ -8,7 +8,7 @@ test that ITransport.loseConnection() works for process transports. """ -import sys +import sys, _preamble from twisted.internet.error import ConnectionDone from twisted.internet import stdio, protocol diff -Nru twisted-12.0.0/twisted/test/stdio_test_producer.py twisted-12.2.0/twisted/test/stdio_test_producer.py --- twisted-12.0.0/twisted/test/stdio_test_producer.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/stdio_test_producer.py 2012-01-23 22:55:41.000000000 +0000 @@ -8,7 +8,7 @@ that process transports implement IProducer properly. """ -import sys +import sys, _preamble from twisted.internet import stdio, protocol from twisted.python import log, reflect diff -Nru twisted-12.0.0/twisted/test/stdio_test_write.py twisted-12.2.0/twisted/test/stdio_test_write.py --- twisted-12.0.0/twisted/test/stdio_test_write.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/stdio_test_write.py 2012-01-23 22:55:41.000000000 +0000 @@ -8,7 +8,7 @@ ITransport.write() works for process transports. """ -import sys +import sys, _preamble from twisted.internet import stdio, protocol from twisted.python import reflect @@ -29,4 +29,3 @@ from twisted.internet import reactor stdio.StandardIO(WriteChild()) reactor.run() - diff -Nru twisted-12.0.0/twisted/test/stdio_test_writeseq.py twisted-12.2.0/twisted/test/stdio_test_writeseq.py --- twisted-12.0.0/twisted/test/stdio_test_writeseq.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/stdio_test_writeseq.py 2012-01-23 22:55:41.000000000 +0000 @@ -8,7 +8,7 @@ ITransport.writeSequence() works for process transports. """ -import sys +import sys, _preamble from twisted.internet import stdio, protocol from twisted.python import reflect diff -Nru twisted-12.0.0/twisted/test/test_amp.py twisted-12.2.0/twisted/test/test_amp.py --- twisted-12.0.0/twisted/test/test_amp.py 2011-09-23 12:30:19.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_amp.py 2012-06-07 14:09:07.000000000 +0000 @@ -9,7 +9,8 @@ import datetime import decimal -from zope.interface.verify import verifyObject +from zope.interface import implements +from zope.interface.verify import verifyClass, verifyObject from twisted.python.util import setIDFunction from twisted.python import filepath @@ -654,7 +655,7 @@ self.sender.expectError() callResult = self.dispatcher.callRemote(Hello, hello='world') - callResult.addCallback(lambda result: 1 / 0) + callResult.addCallback(lambda result: 1 // 0) self.dispatcher.ampBoxReceived(amp.AmpBox({ 'hello': "yay", 'print': "ignored", '_answer': "1"})) @@ -670,7 +671,7 @@ self.sender.expectError() callResult = self.dispatcher.callRemote(Hello, hello='world') - callResult.addErrback(lambda result: 1 / 0) + callResult.addErrback(lambda result: 1 // 0) self.dispatcher.ampBoxReceived(amp.AmpBox({ '_error': '1', '_error_code': 'bugs', @@ -2946,6 +2947,145 @@ +class UNIXStringTransport(object): + """ + An in-memory implementation of L{interfaces.IUNIXTransport} which collects + all data given to it for later inspection. + + @ivar _queue: A C{list} of the data which has been given to this transport, + eg via C{write} or C{sendFileDescriptor}. Elements are two-tuples of a + string (identifying the destination of the data) and the data itself. + """ + implements(interfaces.IUNIXTransport) + + def __init__(self, descriptorFuzz): + """ + @param descriptorFuzz: An offset to apply to descriptors. + @type descriptorFuzz: C{int} + """ + self._fuzz = descriptorFuzz + self._queue = [] + + + def sendFileDescriptor(self, descriptor): + self._queue.append(( + 'fileDescriptorReceived', descriptor + self._fuzz)) + + + def write(self, data): + self._queue.append(('dataReceived', data)) + + + def writeSequence(self, seq): + for data in seq: + self.write(data) + + + def loseConnection(self): + self._queue.append(('connectionLost', Failure(ConnectionLost()))) + + + def getHost(self): + return UNIXAddress('/tmp/some-path') + + + def getPeer(self): + return UNIXAddress('/tmp/another-path') + +# Minimal evidence that we got the signatures right +verifyClass(interfaces.ITransport, UNIXStringTransport) +verifyClass(interfaces.IUNIXTransport, UNIXStringTransport) + + +class DescriptorTests(unittest.TestCase): + """ + Tests for L{amp.Descriptor}, an argument type for passing a file descriptor + over an AMP connection over a UNIX domain socket. + """ + def setUp(self): + self.fuzz = 3 + self.transport = UNIXStringTransport(descriptorFuzz=self.fuzz) + self.protocol = amp.BinaryBoxProtocol( + amp.BoxDispatcher(amp.CommandLocator())) + self.protocol.makeConnection(self.transport) + + + def test_fromStringProto(self): + """ + L{Descriptor.fromStringProto} constructs a file descriptor value by + extracting a previously received file descriptor corresponding to the + wire value of the argument from the L{_DescriptorExchanger} state of the + protocol passed to it. + + This is a whitebox test which involves direct L{_DescriptorExchanger} + state inspection. + """ + argument = amp.Descriptor() + self.protocol.fileDescriptorReceived(5) + self.protocol.fileDescriptorReceived(3) + self.protocol.fileDescriptorReceived(1) + self.assertEqual( + 5, argument.fromStringProto("0", self.protocol)) + self.assertEqual( + 3, argument.fromStringProto("1", self.protocol)) + self.assertEqual( + 1, argument.fromStringProto("2", self.protocol)) + self.assertEqual({}, self.protocol._descriptors) + + + def test_toStringProto(self): + """ + To send a file descriptor, L{Descriptor.toStringProto} uses the + L{IUNIXTransport.sendFileDescriptor} implementation of the transport of + the protocol passed to it to copy the file descriptor. Each subsequent + descriptor sent over a particular AMP connection is assigned the next + integer value, starting from 0. The base ten string representation of + this value is the byte encoding of the argument. + + This is a whitebox test which involves direct L{_DescriptorExchanger} + state inspection and mutation. + """ + argument = amp.Descriptor() + self.assertEqual("0", argument.toStringProto(2, self.protocol)) + self.assertEqual( + ("fileDescriptorReceived", 2 + self.fuzz), self.transport._queue.pop(0)) + self.assertEqual("1", argument.toStringProto(4, self.protocol)) + self.assertEqual( + ("fileDescriptorReceived", 4 + self.fuzz), self.transport._queue.pop(0)) + self.assertEqual("2", argument.toStringProto(6, self.protocol)) + self.assertEqual( + ("fileDescriptorReceived", 6 + self.fuzz), self.transport._queue.pop(0)) + self.assertEqual({}, self.protocol._descriptors) + + + def test_roundTrip(self): + """ + L{amp.Descriptor.fromBox} can interpret an L{amp.AmpBox} constructed by + L{amp.Descriptor.toBox} to reconstruct a file descriptor value. + """ + name = "alpha" + strings = {} + descriptor = 17 + sendObjects = {name: descriptor} + + argument = amp.Descriptor() + argument.toBox(name, strings, sendObjects.copy(), self.protocol) + + receiver = amp.BinaryBoxProtocol( + amp.BoxDispatcher(amp.CommandLocator())) + for event in self.transport._queue: + getattr(receiver, event[0])(*event[1:]) + + receiveObjects = {} + argument.fromBox(name, strings.copy(), receiveObjects, receiver) + + # Make sure we got the descriptor. Adjust by fuzz to be more convincing + # of having gone through L{IUNIXTransport.sendFileDescriptor}, not just + # converted to a string and then parsed back into an integer. + self.assertEqual(descriptor + self.fuzz, receiveObjects[name]) + + + class DateTimeTests(unittest.TestCase): """ Tests for L{amp.DateTime}, L{amp._FixedOffsetTZInfo}, and L{amp.utc}. diff -Nru twisted-12.0.0/twisted/test/test_application.py twisted-12.2.0/twisted/test/test_application.py --- twisted-12.0.0/twisted/test/test_application.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_application.py 2012-06-07 14:09:07.000000000 +0000 @@ -476,7 +476,7 @@ def testBrokenTimer(self): d = defer.Deferred() - t = internet.TimerService(1, lambda: 1 / 0) + t = internet.TimerService(1, lambda: 1 // 0) oldFailed = t._failed def _failed(why): oldFailed(why) @@ -584,7 +584,7 @@ """ reactor = MemoryReactor() - factory = object() + factory = protocol.ClientFactory() t = internet.TCPClient('127.0.0.1', 1234, factory, reactor=reactor) t.startService() self.assertEqual( @@ -598,7 +598,7 @@ """ reactor = MemoryReactor() - factory = object() + factory = protocol.Factory() t = internet.TCPServer(1234, factory, reactor=reactor) t.startService() self.assertEqual(reactor.tcpServers.pop()[:2], (1234, factory)) @@ -614,7 +614,7 @@ """ reactor = MemoryReactor() - factory = object() + factory = protocol.ClientFactory() t = internet.TCPClient('127.0.0.1', 1234, factory, reactor=reactor) t.startService() self.assertEqual( diff -Nru twisted-12.0.0/twisted/test/test_banana.py twisted-12.2.0/twisted/test/test_banana.py --- twisted-12.0.0/twisted/test/test_banana.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_banana.py 2012-06-07 14:09:07.000000000 +0000 @@ -111,7 +111,7 @@ self.enc.sendEncoded(smallest) encoded = self.io.getvalue() self.io.truncate(0) - self.enc.setPrefixLimit(self.enc.prefixLimit / 2) + self.enc.setPrefixLimit(self.enc.prefixLimit // 2) self.assertRaises(banana.BananaError, self.enc.dataReceived, encoded) @@ -139,7 +139,7 @@ self.enc.sendEncoded(largest) encoded = self.io.getvalue() self.io.truncate(0) - self.enc.setPrefixLimit(self.enc.prefixLimit / 2) + self.enc.setPrefixLimit(self.enc.prefixLimit // 2) self.assertRaises(banana.BananaError, self.enc.dataReceived, encoded) diff -Nru twisted-12.0.0/twisted/test/test_compat.py twisted-12.2.0/twisted/test/test_compat.py --- twisted-12.0.0/twisted/test/test_compat.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_compat.py 2012-07-14 21:49:36.000000000 +0000 @@ -6,11 +6,12 @@ Tests for L{twisted.python.compat}. """ -import types, socket +import os, tempfile, types, socket from twisted.trial import unittest -from twisted.python.compat import set, frozenset, reduce +from twisted.python.filepath import FilePath +from twisted.python.compat import set, frozenset, reduce, execfile @@ -80,11 +81,12 @@ self.assertEqual(lst1, lst2) def testIsinstance(self): - self.assert_(isinstance(u'hi', types.StringTypes)) - self.assert_(isinstance(self, unittest.TestCase)) - # I'm pretty sure it's impossible to implement this - # without replacing isinstance on 2.2 as well :( - # self.assert_(isinstance({}, dict)) + """ + The current object is an instance of + unittest.TestCase. + """ + self.assertTrue(isinstance(self, unittest.TestCase)) + def testStrip(self): self.assertEqual(' x '.lstrip(' '), 'x ') @@ -182,7 +184,7 @@ """ a = frozenset(['a', 'b']) self.assertRaises(AttributeError, getattr, a, "add") - self.assertEqual(list(a), ['a', 'b']) + self.assertEqual(sorted(a), ['a', 'b']) b = frozenset(['r', 's']) d = a.union(b) @@ -197,3 +199,54 @@ """ self.assertEqual(15, reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])) self.assertEqual(16, reduce(lambda x, y: x + y, [1, 2, 3, 4, 5], 1)) + + + +class ExecfileCompatTestCase(unittest.TestCase): + """ + Tests for the Python 3-friendly L{execfile} implementation. + """ + + def writeScript(self, content): + """ + Write L{content} to a new temporary file, returning the L{FilePath} + for the new file. + """ + script = FilePath(self.mktemp()) + script.setContent(content.encode("ascii")) + return script + + + def test_execfileGlobals(self): + """ + L{execfile} executes the specified file in the given global namespace. + """ + script = self.writeScript("foo += 1\n") + globalNamespace = {"foo": 1} + execfile(script.path, globalNamespace) + self.assertEqual(2, globalNamespace["foo"]) + + + def test_execfileGlobalsAndLocals(self): + """ + L{execfile} executes the specified file in the given global and local + namespaces. + """ + script = self.writeScript("foo += 1\n") + globalNamespace = {"foo": 10} + localNamespace = {"foo": 20} + execfile(script.path, globalNamespace, localNamespace) + self.assertEqual(10, globalNamespace["foo"]) + self.assertEqual(21, localNamespace["foo"]) + + + def test_execfileUniversalNewlines(self): + """ + L{execfile} reads in the specified file using universal newlines so + that scripts written on one platform will work on another. + """ + for lineEnding in "\n", "\r", "\r\n": + script = self.writeScript("foo = 'okay'" + lineEnding) + globalNamespace = {"foo": None} + execfile(script.path, globalNamespace) + self.assertEqual("okay", globalNamespace["foo"]) diff -Nru twisted-12.0.0/twisted/test/test_defer.py twisted-12.2.0/twisted/test/test_defer.py --- twisted-12.0.0/twisted/test/test_defer.py 2011-08-01 20:06:32.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_defer.py 2012-06-07 14:09:07.000000000 +0000 @@ -240,7 +240,7 @@ def testCallbackErrors(self): l = [] - d = defer.Deferred().addCallback(lambda _: 1 / 0).addErrback(l.append) + d = defer.Deferred().addCallback(lambda _: 1 // 0).addErrback(l.append) d.callback(1) self.assert_(isinstance(l[0].value, ZeroDivisionError)) l = [] @@ -1098,7 +1098,7 @@ compare equal to instances of other types. """ try: - 1 / 0 + 1 // 0 except: firstFailure = failure.Failure() @@ -1565,7 +1565,7 @@ and its final result (the one not handled by any callback) is an exception, that exception will be logged immediately. """ - defer.Deferred().addCallback(lambda x: 1 / 0).callback(1) + defer.Deferred().addCallback(lambda x: 1 // 0).callback(1) gc.collect() self._check() @@ -1575,7 +1575,7 @@ """ def _subErrorLogWithInnerFrameRef(): d = defer.Deferred() - d.addCallback(lambda x: 1 / 0) + d.addCallback(lambda x: 1 // 0) d.callback(1) _subErrorLogWithInnerFrameRef() @@ -1588,7 +1588,7 @@ """ def _subErrorLogWithInnerFrameCycle(): d = defer.Deferred() - d.addCallback(lambda x, d=d: 1 / 0) + d.addCallback(lambda x, d=d: 1 // 0) d._d = d d.callback(1) diff -Nru twisted-12.0.0/twisted/test/test_defgen.py twisted-12.2.0/twisted/test/test_defgen.py --- twisted-12.0.0/twisted/test/test_defgen.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_defgen.py 2012-06-07 14:09:07.000000000 +0000 @@ -1,4 +1,9 @@ -from __future__ import generators, nested_scopes +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.internet.defer.deferredGenerator} and related APIs. +""" import sys @@ -115,7 +120,7 @@ def _genBuggy(self): yield waitForDeferred(getThing()) - 1/0 + 1//0 _genBuggy = deferredGenerator(_genBuggy) diff -Nru twisted-12.0.0/twisted/test/test_epoll.py twisted-12.2.0/twisted/test/test_epoll.py --- twisted-12.0.0/twisted/test/test_epoll.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_epoll.py 2012-02-19 19:24:21.000000000 +0000 @@ -80,7 +80,6 @@ self.assertRaises(TypeError, _epoll.epoll, ()) self.assertRaises(TypeError, _epoll.epoll, ['foo']) self.assertRaises(TypeError, _epoll.epoll, {}) - self.assertRaises(TypeError, _epoll.epoll) def test_add(self): diff -Nru twisted-12.0.0/twisted/test/test_failure.py twisted-12.2.0/twisted/test/test_failure.py --- twisted-12.0.0/twisted/test/test_failure.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_failure.py 2012-06-07 14:09:07.000000000 +0000 @@ -4,6 +4,7 @@ """ Test cases for failure module. """ +from __future__ import division import re import sys diff -Nru twisted-12.0.0/twisted/test/test_formmethod.py twisted-12.2.0/twisted/test/test_formmethod.py --- twisted-12.0.0/twisted/test/test_formmethod.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_formmethod.py 2012-08-01 11:08:41.000000000 +0000 @@ -19,7 +19,16 @@ self.assertEqual(arg.coerce(val), result) for val in badValues: self.assertRaises(formmethod.InputError, arg.coerce, val) - + + + def test_argument(self): + """ + Test that corce correctly raises NotImplementedError. + """ + arg = formmethod.Argument("name") + self.assertRaises(NotImplementedError, arg.coerce, "") + + def testString(self): self.argTest(formmethod.String, [("a", "a"), (1, "1"), ("", "")], ()) self.argTest(formmethod.String, [("ab", "ab"), ("abc", "abc")], ("2", ""), min=2) @@ -53,6 +62,18 @@ tests = [("yes", 1), ("", 0), ("False", 0), ("no", 0)] self.argTest(formmethod.Boolean, tests, ()) + + def test_file(self): + """ + Test the correctness of the coerce function. + """ + arg = formmethod.File("name", allowNone=0) + self.assertEqual(arg.coerce("something"), "something") + self.assertRaises(formmethod.InputError, arg.coerce, None) + arg2 = formmethod.File("name") + self.assertEqual(arg2.coerce(None), None) + + def testDate(self): goodTests = { ("2002", "12", "21"): (2002, 12, 21), diff -Nru twisted-12.0.0/twisted/test/test_ftp.py twisted-12.2.0/twisted/test/test_ftp.py --- twisted-12.0.0/twisted/test/test_ftp.py 2012-01-15 18:31:09.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_ftp.py 2012-07-15 04:35:33.000000000 +0000 @@ -81,9 +81,19 @@ self.dirPath = filepath.FilePath(self.directory) # Start the server - p = portal.Portal(ftp.FTPRealm(self.directory)) + p = portal.Portal(ftp.FTPRealm( + anonymousRoot=self.directory, + userHome=self.directory, + )) p.registerChecker(checkers.AllowAnonymousAccess(), credentials.IAnonymous) + + users_checker = checkers.InMemoryUsernamePasswordDatabaseDontUse() + self.username = "test-user" + self.password = "test-password" + users_checker.addUser(self.username, self.password) + p.registerChecker(users_checker, credentials.IUsernamePassword) + self.factory = ftp.FTPFactory(portal=p, userAnonymous=self.userAnonymous) port = reactor.listenTCP(0, self.factory, interface="127.0.0.1") @@ -159,6 +169,15 @@ ['230 Anonymous login ok, access restrictions apply.'], chainDeferred=d) + def _userLogin(self): + """Authenticates the FTP client using the test account.""" + d = self.assertCommandResponse( + 'USER %s' % (self.username), + ['331 Password required for %s.' % (self.username)]) + return self.assertCommandResponse( + 'PASS %s' % (self.password), + ['230 User logged in, proceed'], + chainDeferred=d) class FTPAnonymousTestCase(FTPServerTestCase): @@ -342,12 +361,56 @@ self.serverProtocol.transport.loseConnection() testPASV = defer.deferredGenerator(testPASV) - def testSYST(self): + def test_SYST(self): + """SYST command will always return UNIX Type: L8""" d = self._anonymousLogin() self.assertCommandResponse('SYST', ["215 UNIX Type: L8"], chainDeferred=d) return d + def test_RNFRandRNTO(self): + """ + Sending the RNFR command followed by RNTO, with valid filenames, will + perform a successful rename operation. + """ + # Create user home folder with a 'foo' file. + self.dirPath.child(self.username).createDirectory() + self.dirPath.child(self.username).child('foo').touch() + + d = self._userLogin() + self.assertCommandResponse( + 'RNFR foo', + ["350 Requested file action pending further information."], + chainDeferred=d) + self.assertCommandResponse( + 'RNTO bar', + ["250 Requested File Action Completed OK"], + chainDeferred=d) + + def check_rename(result): + self.assertTrue( + self.dirPath.child(self.username).child('bar').exists()) + return result + + d.addCallback(check_rename) + return d + + def test_RNFRwithoutRNTO(self): + """ + Sending the RNFR command followed by any command other than RNTO + should return an error informing users that RNFR should be followed + by RNTO. + """ + d = self._anonymousLogin() + self.assertCommandResponse( + 'RNFR foo', + ["350 Requested file action pending further information."], + chainDeferred=d) + self.assertCommandFailed( + 'OTHER don-tcare', + ["503 Incorrect sequence of commands: RNTO required after RNFR"], + chainDeferred=d) + return d def test_portRangeForwardError(self): """ @@ -448,6 +511,37 @@ d2.addErrback(eb) return defer.gatherResults([d1, d2]) + def test_RETRreadError(self): + """ + Any errors during reading a file inside a RETR should be returned to + the client. + """ + # Make a failing file reading. + class FailingFileReader(ftp._FileReader): + def send(self, consumer): + return defer.fail(ftp.IsADirectoryError("blah")) + + def failingRETR(a, b): + return defer.succeed(FailingFileReader(None)) + + # Monkey patch the shell so it returns a file reader that will + # fail. + self.patch(ftp.FTPAnonymousShell, 'openForReading', failingRETR) + + def check_response(failure): + self.flushLoggedErrors() + failure.trap(ftp.CommandFailed) + self.assertEqual( + failure.value.args[0][0], + "125 Data connection already open, starting transfer") + self.assertEqual( + failure.value.args[0][1], + "550 blah: is a directory") + + proto = _BufferingProtocol() + d = self.client.retrieveFile('failing_file', proto) + d.addErrback(check_response) + return d class FTPServerPasvDataConnectionTestCase(FTPServerTestCase): diff -Nru twisted-12.0.0/twisted/test/test_import.py twisted-12.2.0/twisted/test/test_import.py --- twisted-12.0.0/twisted/test/test_import.py 2012-01-06 13:16:05.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_import.py 2012-03-07 17:27:04.000000000 +0000 @@ -64,7 +64,6 @@ from twisted.python import log from twisted.python import reflect from twisted.python import usage - from twisted.python import otp def test_protocols(self): """ diff -Nru twisted-12.0.0/twisted/test/test_journal.py twisted-12.2.0/twisted/test/test_journal.py --- twisted-12.0.0/twisted/test/test_journal.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_journal.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,250 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Testing for twisted.persisted.journal. -""" - -import shutil, os.path, sys - -from twisted.trial import unittest - -from twisted.persisted.journal.base import ICommand, MemoryJournal, serviceCommand, ServiceWrapperCommand, command, Wrappable -from twisted.persisted.journal.picklelog import DirDBMLog -from twisted.python import deprecate, versions -from zope.interface import implements - -from twisted.python.test.modules_helpers import TwistedModulesTestCase - - -class AddTime: - - implements(ICommand) - - def execute(self, svc, cmdtime): - svc.values["time"] = cmdtime - - -class Counter(Wrappable): - - objectType = "counter" - - def __init__(self, uid): - self.uid = uid - self.x = 0 - - - def getUid(self): - return self.uid - - - def _increment(self): - self.x += 1 - - - increment = command("_increment") - - - -class Service: - - def __init__(self, logpath, journalpath): - log = DirDBMLog(logpath) - self.journal = MemoryJournal(log, self, journalpath, self._gotData) - self.journal.updateFromLog() - - - def _gotData(self, result): - if result is None: - self.values = {} - self.counters = {} - else: - self.values, self.counters = result - - - def _makeCounter(self, id): - c = Counter(id) - self.counters[id] = c - return c - - makeCounter = serviceCommand("_makeCounter") - - - def loadObject(self, type, id): - if type != "counter": raise ValueError - return self.counters[id] - - - def _add(self, key, value): - """Add a new entry.""" - self.values[key] = value - - - def _delete(self, key): - """ - Delete an entry. - """ - del self.values[key] - - - def get(self, key): - """ - Return value of an entry. - """ - return self.values[key] - - - def addtime(self, journal): - """ - Set a key 'time' with the current time. - """ - journal.executeCommand(AddTime()) - - # and now the command wrappers - - add = serviceCommand("_add") - - delete = serviceCommand("_delete") - - - -class JournalTestCase(unittest.TestCase): - - def setUp(self): - self.logpath = self.mktemp() - self.journalpath = self.mktemp() - self.svc = Service(self.logpath, self.journalpath) - - - def tearDown(self): - if hasattr(self, "svc"): - del self.svc - # delete stuff? ... - if os.path.isdir(self.logpath): - shutil.rmtree(self.logpath) - if os.path.exists(self.logpath): - os.unlink(self.logpath) - if os.path.isdir(self.journalpath): - shutil.rmtree(self.journalpath) - if os.path.exists(self.journalpath): - os.unlink(self.journalpath) - - - def testCommandExecution(self): - svc = self.svc - svc.add(svc.journal, "foo", "bar") - self.assertEqual(svc.get("foo"), "bar") - - svc.delete(svc.journal, "foo") - self.assertRaises(KeyError, svc.get, "foo") - - - def testLogging(self): - svc = self.svc - log = self.svc.journal.log - j = self.svc.journal - svc.add(j, "foo", "bar") - svc.add(j, 1, "hello") - svc.delete(j, "foo") - - commands = [ServiceWrapperCommand("_add", ("foo", "bar")), - ServiceWrapperCommand("_add", (1, "hello")), - ServiceWrapperCommand("_delete", ("foo",))] - - self.assertEqual(log.getCurrentIndex(), 3) - for i in range(1, 4): - for a, b in zip(commands[i-1:], [c for t, c in log.getCommandsSince(i)]): - self.assertEqual(a, b) - - - def testRecovery(self): - svc = self.svc - j = svc.journal - svc.add(j, "foo", "bar") - svc.add(j, 1, "hello") - # we sync *before* delete to make sure commands get executed - svc.journal.sync((svc.values, svc.counters)) - svc.delete(j, "foo") - d = svc.makeCounter(j, 1) - d.addCallback(lambda c, j=j: c.increment(j)) - del svc, self.svc - - # first, load from snapshot - svc = Service(self.logpath, self.journalpath) - self.assertEqual(svc.values, {1: "hello"}) - self.assertEqual(svc.counters[1].x, 1) - del svc - - # now, tamper with log, and then try - f = open(self.journalpath, "w") - f.write("sfsdfsdfsd") - f.close() - svc = Service(self.logpath, self.journalpath) - self.assertEqual(svc.values, {1: "hello"}) - self.assertEqual(svc.counters[1].x, 1) - - - def testTime(self): - svc = self.svc - svc.addtime(svc.journal) - t = svc.get("time") - - log = self.svc.journal.log - (t2, c), = log.getCommandsSince(1) - self.assertEqual(t, t2) - - - -class JournalDeprecationTest(TwistedModulesTestCase): - """ - Tests for twisted.persisted.journal being deprecated. - """ - - def setUp(self): - """ - Prepare for the deprecation test, by making sure that - twisted.persisted.journal isn't imported. - """ - self.replaceSysModules(sys.modules.copy()) - mods = [] - for mod in sys.modules: - if mod.startswith("twisted.persisted.journal"): - mods.append(mod) - for mod in mods: - del(sys.modules[mod]) - - - def uniquify(self, listOfStuff): - """ - Remove duplicate items from a list - """ - for i in range(len(listOfStuff)): - j = i+1; - while j < len(listOfStuff): - if listOfStuff[j] == listOfStuff[i]: - del(listOfStuff[j]) - else: - j += 1 - - - def test_deprecated(self): - """ - Make sure that twisted.persisted.journal is deprecated, and - check the text of its deprecation warning. - """ - from twisted.persisted import journal - warnings = self.flushWarnings([self.test_deprecated]) - - # because for some reason deprecate.deprecatedModuleAttribute causes a warning to be - # emitted twice in this case. Bug will be filed - self.uniquify(warnings) - - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - deprecate.getDeprecationWarningString(journal, - versions.Version('twisted', 11, 0, 0)) + - ": Use a different persistence library. This one is no longer maintained.") - diff -Nru twisted-12.0.0/twisted/test/test_log.py twisted-12.2.0/twisted/test/test_log.py --- twisted-12.0.0/twisted/test/test_log.py 2011-08-14 01:01:36.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_log.py 2012-08-03 11:10:08.000000000 +0000 @@ -5,7 +5,7 @@ Tests for L{twisted.python.log}. """ -import os, sys, time, logging, warnings +import os, sys, time, logging, warnings, calendar from cStringIO import StringIO from twisted.trial import unittest @@ -36,7 +36,7 @@ i = catcher.pop() self.assertEqual(i["message"][0], "test") self.assertEqual(i["testShouldCatch"], True) - self.failUnless(i.has_key("time")) + self.assertIn("time", i) self.assertEqual(len(catcher), 0) @@ -83,7 +83,7 @@ L1 = [] L2 = [] def broken(events): - 1 / 0 + 1 // 0 for observer in [L1.append, broken, L2.append]: log.addObserver(observer) @@ -258,13 +258,13 @@ class EvilStr: def __str__(self): - 1/0 + 1//0 class EvilRepr: def __str__(self): return "Happy Evil Repr" def __repr__(self): - 1/0 + 1//0 class EvilReprStr(EvilStr, EvilRepr): pass @@ -391,9 +391,7 @@ Test the method of L{FileLogObserver} which turns a timestamp into a human-readable string. """ - # There is no function in the time module which converts a UTC time - # tuple to a timestamp. - when = time.mktime((2001, 2, 3, 4, 5, 6, 7, 8, 0)) - time.timezone + when = calendar.timegm((2001, 2, 3, 4, 5, 6, 7, 8, 0)) # Pretend to be in US/Eastern for a moment self.flo.getTimezoneOffset = lambda when: 18000 diff -Nru twisted-12.0.0/twisted/test/test_monkey.py twisted-12.2.0/twisted/test/test_monkey.py --- twisted-12.0.0/twisted/test/test_monkey.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_monkey.py 2012-08-01 10:16:42.000000000 +0000 @@ -151,7 +151,7 @@ def _(): self.assertEqual(self.testObject.foo, 'haha') self.assertEqual(self.testObject.bar, 'blahblah') - raise RuntimeError, "Something went wrong!" + raise RuntimeError("Something went wrong!") self.monkeyPatcher.addPatch(self.testObject, 'foo', 'haha') self.monkeyPatcher.addPatch(self.testObject, 'bar', 'blahblah') diff -Nru twisted-12.0.0/twisted/test/test_newcred.py twisted-12.2.0/twisted/test/test_newcred.py --- twisted-12.0.0/twisted/test/test_newcred.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_newcred.py 2012-06-07 13:15:27.000000000 +0000 @@ -71,7 +71,7 @@ self.avatars = {} def requestAvatar(self, avatarId, mind, *interfaces): - if self.avatars.has_key(avatarId): + if avatarId in self.avatars: avatar = self.avatars[avatarId] else: avatar = TestAvatar(avatarId) diff -Nru twisted-12.0.0/twisted/test/test_paths.py twisted-12.2.0/twisted/test/test_paths.py --- twisted-12.0.0/twisted/test/test_paths.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_paths.py 2012-03-13 23:29:48.000000000 +0000 @@ -15,6 +15,8 @@ from twisted.trial import unittest +from zope.interface.verify import verifyObject + class AbstractFilePathTestCase(unittest.TestCase): @@ -68,7 +70,8 @@ ["a", "b", "c"]) def test_segmentsFromNegative(self): - """Verify that segmentsFrom notices when the ancestor isn't an ancestor. + """ + Verify that segmentsFrom notices when the ancestor isn't an ancestor. """ self.assertRaises( ValueError, @@ -103,7 +106,8 @@ def test_validSubdir(self): - """Verify that a valid subdirectory will show up as a directory, but not as a + """ + Verify that a valid subdirectory will show up as a directory, but not as a file, not as a symlink, and be listable. """ sub1 = self.path.child('sub1') @@ -273,7 +277,7 @@ def zipit(dirname, zfname): """ - create a zipfile on zfname, containing the contents of dirname' + Create a zipfile on zfname, containing the contents of dirname' """ zf = zipfile.ZipFile(zfname, "w") for root, ignored, files, in os.walk(dirname): @@ -299,6 +303,14 @@ self.all = [x.replace(self.cmn, self.cmn + '.zip') for x in self.all] + def test_verifyObject(self): + """ + ZipPaths implement IFilePath. + """ + + self.assertTrue(verifyObject(filepath.IFilePath, self.path)) + + def test_zipPathRepr(self): """ Make sure that invoking ZipPath's repr prints the correct class name @@ -643,6 +655,15 @@ Test various L{FilePath} path manipulations. """ + + def test_verifyObject(self): + """ + FilePaths implement IFilePath. + """ + + self.assertTrue(verifyObject(filepath.IFilePath, self.path)) + + def test_chmod(self): """ L{FilePath.chmod} modifies the permissions of @@ -926,10 +947,11 @@ self.assertRaises(filepath.InsecurePath, self.path.child, r"C:randomfile") if platform.getType() != 'win32': - testInsecureWin32.skip = "Consider yourself lucky." + testInsecureWin32.skip = "Test will run only on Windows." def testInsecureWin32Whacky(self): - """Windows has 'special' filenames like NUL and CON and COM1 and LPR + """ + Windows has 'special' filenames like NUL and CON and COM1 and LPR and PRN and ... god knows what else. They can be located anywhere in the filesystem. For obvious reasons, we do not wish to normally permit access to these. @@ -939,7 +961,7 @@ self.assertRaises(filepath.InsecurePath, self.path.child, r"C:\CON") if platform.getType() != 'win32': - testInsecureWin32Whacky.skip = "Consider yourself lucky." + testInsecureWin32Whacky.skip = "Test will run only on Windows." def testComparison(self): self.assertEqual(filepath.FilePath('a'), @@ -1558,8 +1580,8 @@ test_statinfoNumbersAreValid.skip = True test_getPermissions_POSIX.skip = True else: - test_statinfoBitsNotImplementedInWindows.skip = True - test_getPermissions_Windows.skip = True + test_statinfoBitsNotImplementedInWindows.skip = "Test will run only on Windows." + test_getPermissions_Windows.skip = "Test will run only on Windows." diff -Nru twisted-12.0.0/twisted/test/test_process.py twisted-12.2.0/twisted/test/test_process.py --- twisted-12.0.0/twisted/test/test_process.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_process.py 2012-07-08 18:39:59.000000000 +0000 @@ -201,13 +201,14 @@ if childFD == 1: self.stages.append(2) if self.data != "abcd": - raise RuntimeError + raise RuntimeError( + "Data was %r instead of 'abcd'" % (self.data,)) self.transport.write("1234") elif childFD == 2: self.stages.append(3) if self.err != "1234": - print 'err != 1234: ' + repr(self.err) - raise RuntimeError() + raise RuntimeError( + "Err was %r instead of '1234'" % (self.err,)) self.transport.write("abcd") self.stages.append(4) elif childFD == 0: @@ -1162,7 +1163,7 @@ # This script runs until we disconnect its transport. pythonExecutable = sys.executable - scriptPath = util.sibpath(__file__, "process_twisted.py") + scriptPath = util.sibpath(__file__, "process_echoer.py") class ErrorInProcessEnded(protocol.ProcessProtocol): """ @@ -1254,7 +1255,7 @@ @ivar pipeCount: count the number of time that C{os.pipe} has been called. @type pipeCount: C{int} - @ivar raiseWaitPid: if set, subsequent calls to waitpid will raise an + @ivar raiseWaitPid: if set, subsequent calls to waitpid will raise the error specified. @type raiseWaitPid: C{None} or a class @@ -1275,6 +1276,10 @@ @ivar path: the path returned by C{os.path.expanduser}. @type path: C{str} + + @ivar raiseKill: if set, subsequent call to kill will raise the error + specified. + @type raiseKill: C{None} or an exception instance. """ exited = False raiseExec = False @@ -1286,6 +1291,7 @@ euid = 0 egid = 0 path = None + raiseKill = None def __init__(self): """ @@ -1534,6 +1540,7 @@ """ return 0, 0, 1, 2 + def listdir(self, path): """ Override C{os.listdir}, returning fake contents of '/dev/fd' @@ -1541,6 +1548,16 @@ return "-1", "-2" + def kill(self, pid, signalID): + """ + Override C{os.kill}: save the action and raise C{self.raiseKill} if + specified. + """ + self.actions.append(('kill', pid, signalID)) + if self.raiseKill is not None: + raise self.raiseKill + + if process is not None: class DumbProcessWriter(process.ProcessWriter): @@ -1977,6 +1994,69 @@ ('setregid', 1235, 1234), ('setreuid', 1237, 1236)]) + def test_kill(self): + """ + L{process.Process.signalProcess} calls C{os.kill} translating the given + signal string to the PID. + """ + self.mockos.child = False + self.mockos.waitChild = (0, 0) + cmd = '/mock/ouch' + p = TrivialProcessProtocol(None) + proc = reactor.spawnProcess(p, cmd, ['ouch'], env=None, usePTY=False) + proc.signalProcess("KILL") + self.assertEqual(self.mockos.actions, + [('fork', False), 'waitpid', ('kill', 21, signal.SIGKILL)]) + + + def test_killExited(self): + """ + L{process.Process.signalProcess} raises L{error.ProcessExitedAlready} + if the process has exited. + """ + self.mockos.child = False + cmd = '/mock/ouch' + p = TrivialProcessProtocol(None) + proc = reactor.spawnProcess(p, cmd, ['ouch'], env=None, usePTY=False) + # We didn't specify a waitpid value, so the waitpid call in + # registerReapProcessHandler has already reaped the process + self.assertRaises(error.ProcessExitedAlready, + proc.signalProcess, "KILL") + + + def test_killExitedButNotDetected(self): + """ + L{process.Process.signalProcess} raises L{error.ProcessExitedAlready} + if the process has exited but that twisted hasn't seen it (for example, + if the process has been waited outside of twisted): C{os.kill} then + raise C{OSError} with C{errno.ESRCH} as errno. + """ + self.mockos.child = False + self.mockos.waitChild = (0, 0) + cmd = '/mock/ouch' + p = TrivialProcessProtocol(None) + proc = reactor.spawnProcess(p, cmd, ['ouch'], env=None, usePTY=False) + self.mockos.raiseKill = OSError(errno.ESRCH, "Not found") + self.assertRaises(error.ProcessExitedAlready, + proc.signalProcess, "KILL") + + + def test_killErrorInKill(self): + """ + L{process.Process.signalProcess} doesn't mask C{OSError} exceptions if + the errno is different from C{errno.ESRCH}. + """ + self.mockos.child = False + self.mockos.waitChild = (0, 0) + cmd = '/mock/ouch' + p = TrivialProcessProtocol(None) + proc = reactor.spawnProcess(p, cmd, ['ouch'], env=None, usePTY=False) + self.mockos.raiseKill = OSError(errno.EINVAL, "Invalid signal") + err = self.assertRaises(OSError, + proc.signalProcess, "KILL") + self.assertEquals(err.errno, errno.EINVAL) + + class PosixProcessTestCase(unittest.TestCase, PosixProcessBase): # add two non-pty test cases @@ -1994,7 +2074,7 @@ p = Accumulator() d = p.endedDeferred = defer.Deferred() reactor.spawnProcess(p, cmd, - [cmd, "-c", + [cmd, "-c", "import sys; sys.stderr.write('%s')" % (value,)], env=None, path="/tmp", usePTY=self.usePTY) @@ -2400,7 +2480,7 @@ 'import sys, os, time\n' # Give the system a bit of time to notice the closed # descriptor. Another option would be to poll() for HUP - # instead of relying on an os.write to fail with SIGPIPE. + # instead of relying on an os.write to fail with SIGPIPE. # However, that wouldn't work on OS X (or Windows?). 'for i in range(1000):\n' ' os.write(%d, "foo\\n")\n' diff -Nru twisted-12.0.0/twisted/test/test_protocols.py twisted-12.2.0/twisted/test/test_protocols.py --- twisted-12.0.0/twisted/test/test_protocols.py 2011-10-11 12:01:26.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_protocols.py 2012-06-07 14:09:07.000000000 +0000 @@ -232,7 +232,7 @@ t = proto_helpers.StringIOWithoutClosing() a = LineTester() a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.buffer)/packet_size + 1): + for i in range(len(self.buffer) // packet_size + 1): s = self.buffer[i*packet_size:(i+1)*packet_size] a.dataReceived(s) self.assertEqual(self.output, a.received) @@ -254,7 +254,7 @@ clock = task.Clock() a = LineTester(clock) a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.pause_buf)/packet_size + 1): + for i in range(len(self.pause_buf) // packet_size + 1): s = self.pause_buf[i*packet_size:(i+1)*packet_size] a.dataReceived(s) self.assertEqual(self.pause_output1, a.received) @@ -277,7 +277,7 @@ clock = task.Clock() a = LineTester(clock) a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.rawpause_buf)/packet_size + 1): + for i in range(len(self.rawpause_buf) // packet_size + 1): s = self.rawpause_buf[i*packet_size:(i+1)*packet_size] a.dataReceived(s) self.assertEqual(self.rawpause_output1, a.received) @@ -297,7 +297,7 @@ t = proto_helpers.StringIOWithoutClosing() a = LineTester() a.makeConnection(protocol.FileWrapper(t)) - for i in range(len(self.stop_buf)/packet_size + 1): + for i in range(len(self.stop_buf) // packet_size + 1): s = self.stop_buf[i*packet_size:(i+1)*packet_size] a.dataReceived(s) self.assertEqual(self.stop_output, a.received) @@ -455,7 +455,7 @@ for s in self.strings: a.sendString(s) out = t.value() - for i in range(len(out)/packet_size + 1): + for i in range(len(out) // packet_size + 1): s = out[i*packet_size:(i+1)*packet_size] if s: a.dataReceived(s) diff -Nru twisted-12.0.0/twisted/test/test_randbytes.py twisted-12.2.0/twisted/test/test_randbytes.py --- twisted-12.0.0/twisted/test/test_randbytes.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_randbytes.py 2012-04-01 20:07:59.000000000 +0000 @@ -77,25 +77,12 @@ self._check(self.factory._osUrandom) - def test_fileUrandom(self): - """ - L{RandomFactory._fileUrandom} should work as a random source whenever - C{/dev/urandom} is available. - """ - try: - self._check(self.factory._fileUrandom) - except randbytes.SourceNotAvailable: - # The test should only fail in /dev/urandom doesn't exist - self.assertFalse(os.path.exists('/dev/urandom')) - - def test_withoutAnything(self): """ Remove all secure sources and assert it raises a failure. Then try the fallback parameter. """ self.factory._osUrandom = self.errorFactory - self.factory._fileUrandom = self.errorFactory self.assertRaises(randbytes.SecureRandomNotAvailable, self.factory.secureRandom, 18) def wrapper(): diff -Nru twisted-12.0.0/twisted/test/test_reflect.py twisted-12.2.0/twisted/test/test_reflect.py --- twisted-12.0.0/twisted/test/test_reflect.py 2011-11-08 01:51:26.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_reflect.py 2012-07-26 09:12:02.000000000 +0000 @@ -6,7 +6,10 @@ """ import weakref, os -from ihooks import ModuleImporter +try: + from ihooks import ModuleImporter +except ImportError: + ModuleImporter = None try: from collections import deque @@ -294,6 +297,9 @@ Runs all of the tests from L{LookupsTestCase} after installing a custom import hook. """ + if ModuleImporter == None: + skip = "ihooks not available" + def setUp(self): """ Perturb the normal import behavior subtly by installing an import @@ -757,27 +763,111 @@ Test deprecations in twisted.python.reflect """ - def test_macro(self): - """ - Test deprecation of L{reflect.macro}. - """ - result = self.callDeprecated(Version("Twisted", 8, 2, 0), - reflect.macro, "test", __file__, "test = 1") - self.assertEqual(result, 1) - def test_allYourBase(self): """ - Test deprecation of L{reflect.allYourBase}. + Test deprecation of L{reflect.allYourBase}. See #5481 for removal. """ self.callDeprecated( (Version("Twisted", 11, 0, 0), "inspect.getmro"), reflect.allYourBase, DeprecationTestCase) + def test_accumulateBases(self): """ - Test deprecation of L{reflect.accumulateBases}. + Test deprecation of L{reflect.accumulateBases}. See #5481 for removal. """ l = [] self.callDeprecated( (Version("Twisted", 11, 0, 0), "inspect.getmro"), reflect.accumulateBases, DeprecationTestCase, l, None) + + + def lookForDeprecationWarning(self, testMethod, attributeName, warningMsg): + """ + Test deprecation of attribute 'reflect.attributeName' by calling + 'reflect.testMethod' and verifying the warning message + 'reflect.warningMsg' + + @param testMethod: Name of the offending function to be used with + flushWarnings + @type testmethod: C{str} + + @param attributeName: Name of attribute to be checked for deprecation + @type attributeName: C{str} + + @param warningMsg: Deprecation warning message + @type warningMsg: C{str} + """ + warningsShown = self.flushWarnings([testMethod]) + self.assertEqual(len(warningsShown), 1) + self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) + self.assertEqual( + warningsShown[0]['message'], + "twisted.python.reflect." + attributeName + " " + "was deprecated in Twisted 12.1.0: " + warningMsg + ".") + + + def test_settable(self): + """ + Test deprecation of L{reflect.Settable}. + """ + reflect.Settable() + self.lookForDeprecationWarning( + self.test_settable, "Settable", + "Settable is old and untested. Please write your own version of this " + "functionality if you need it") + + + def test_accessorType(self): + """ + Test deprecation of L{reflect.AccessorType}. + """ + reflect.AccessorType(' ', ( ), { }) + self.lookForDeprecationWarning( + self.test_accessorType, "AccessorType", + "AccessorType is old and untested. Please write your own version of " + "this functionality if you need it") + + + def test_propertyAccessor(self): + """ + Test deprecation of L{reflect.PropertyAccessor}. + """ + reflect.PropertyAccessor() + self.lookForDeprecationWarning( + self.test_propertyAccessor, "PropertyAccessor", + "PropertyAccessor is old and untested. Please write your own " + "version of this functionality if you need it") + + + def test_accessor(self): + """ + Test deprecation of L{reflect.Accessor}. + """ + reflect.Accessor() + self.lookForDeprecationWarning( + self.test_accessor, "Accessor", + "Accessor is an implementation for Python 2.1 which is no longer " + "supported by Twisted") + + + def test_originalAccessor(self): + """ + Test deprecation of L{reflect.OriginalAccessor}. + """ + reflect.OriginalAccessor() + self.lookForDeprecationWarning( + self.test_originalAccessor, "OriginalAccessor", + "OriginalAccessor is a reference to class " + "twisted.python.reflect.Accessor which is deprecated") + + + def test_summer(self): + """ + Test deprecation of L{reflect.Summer}. + """ + reflect.Summer() + self.lookForDeprecationWarning( + self.test_summer, "Summer", + "Summer is a child class of twisted.python.reflect.Accessor which " + "is deprecated") diff -Nru twisted-12.0.0/twisted/test/test_sip.py twisted-12.2.0/twisted/test/test_sip.py --- twisted-12.0.0/twisted/test/test_sip.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_sip.py 2012-06-04 21:49:10.000000000 +0000 @@ -86,6 +86,24 @@ """.replace("\n", "\r\n") +# multiline headers (example from RFC 3621). +response_multiline = """\ +SIP/2.0 200 OK +Via: SIP/2.0/UDP server10.biloxi.com + ;branch=z9hG4bKnashds8;received=192.0.2.3 +Via: SIP/2.0/UDP bigbox3.site3.atlanta.com + ;branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2 +Via: SIP/2.0/UDP pc33.atlanta.com + ;branch=z9hG4bK776asdhds ;received=192.0.2.1 +To: Bob ;tag=a6c85cf +From: Alice ;tag=1928301774 +Call-ID: a84b4c76e66710@pc33.atlanta.com +CSeq: 314159 INVITE +Contact: +Content-Type: application/sdp +Content-Length: 0 +\n""".replace("\n", "\r\n") + class TestRealm: def requestAvatar(self, avatarId, mind, *interfaces): return sip.IContact, None, lambda: None @@ -178,6 +196,30 @@ self.assertEqual(m.finished, 1) + def test_multiLine(self): + """ + A header may be split across multiple lines. Subsequent lines begin + with C{" "} or C{"\\t"}. + """ + l = self.l + self.feedMessage(response_multiline) + self.assertEquals(len(l), 1) + m = l[0] + self.assertEquals( + m.headers['via'][0], + "SIP/2.0/UDP server10.biloxi.com;" + "branch=z9hG4bKnashds8;received=192.0.2.3") + self.assertEquals( + m.headers['via'][1], + "SIP/2.0/UDP bigbox3.site3.atlanta.com;" + "branch=z9hG4bK77ef4c2312983.1;received=192.0.2.2") + self.assertEquals( + m.headers['via'][2], + "SIP/2.0/UDP pc33.atlanta.com;" + "branch=z9hG4bK776asdhds ;received=192.0.2.1") + + + class MessageParsingTestCase2(MessageParsingTestCase): """Same as base class, but feed data char by char.""" diff -Nru twisted-12.0.0/twisted/test/test_sslverify.py twisted-12.2.0/twisted/test/test_sslverify.py --- twisted-12.0.0/twisted/test/test_sslverify.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_sslverify.py 2012-07-08 22:08:06.000000000 +0000 @@ -232,22 +232,22 @@ self.assertEqual( c.inspect().split('\n'), ["Certificate For Subject:", - " Organizational Unit Name: Security", - " Organization Name: Twisted Matrix Labs", " Common Name: example.twistedmatrix.com", - " State Or Province Name: Massachusetts", " Country Name: US", " Email Address: nobody@twistedmatrix.com", " Locality Name: Boston", + " Organization Name: Twisted Matrix Labs", + " Organizational Unit Name: Security", + " State Or Province Name: Massachusetts", "", "Issuer:", - " Organizational Unit Name: Security", - " Organization Name: Twisted Matrix Labs", " Common Name: example.twistedmatrix.com", - " State Or Province Name: Massachusetts", " Country Name: US", " Email Address: nobody@twistedmatrix.com", " Locality Name: Boston", + " Organization Name: Twisted Matrix Labs", + " Organizational Unit Name: Security", + " State Or Province Name: Massachusetts", "", "Serial Number: 12345", "Digest: C4:96:11:00:30:C3:EC:EE:A3:55:AA:ED:8C:84:85:18", diff -Nru twisted-12.0.0/twisted/test/test_stdio.py twisted-12.2.0/twisted/test/test_stdio.py --- twisted-12.0.0/twisted/test/test_stdio.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_stdio.py 2012-05-04 18:49:18.000000000 +0000 @@ -364,37 +364,8 @@ ''.join(map(str, range(howMany)))) onConnLost.addCallback(cbLost) return onConnLost - if reactor.__class__.__name__ == 'EPollReactor': - test_normalFileStandardOut.skip = ( - "epoll(7) does not support normal files. See #4429. " - "This should be a todo but technical limitations prevent " - "this.") - elif platform.isWindows(): + + if platform.isWindows(): test_normalFileStandardOut.skip = ( "StandardIO does not accept stdout as an argument to Windows. " "Testing redirection to a file is therefore harder.") - - - def test_normalFileStandardOutGoodEpollError(self): - """ - Using StandardIO with epollreactor with stdout redirected to a - normal file fails with a comprehensible error (until it is - supported, when #4429 is resolved). See also #2259 and #3442. - """ - path = filepath.FilePath(self.mktemp()) - normal = path.open('w') - fd = normal.fileno() - self.addCleanup(normal.close) - exc = self.assertRaises( - RuntimeError, - stdio.StandardIO, protocol.Protocol(), stdout=fd) - - self.assertEqual( - str(exc), - "This reactor does not support this type of file descriptor (fd " - "%d, mode %d) (for example, epollreactor does not support normal " - "files. See #4429)." % (fd, os.fstat(fd).st_mode)) - if reactor.__class__.__name__ != 'EPollReactor': - test_normalFileStandardOutGoodEpollError.skip = ( - "Only epollreactor is expected to fail with stdout redirected " - "to a normal file.") diff -Nru twisted-12.0.0/twisted/test/test_strcred.py twisted-12.2.0/twisted/test/test_strcred.py --- twisted-12.0.0/twisted/test/test_strcred.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_strcred.py 2012-03-12 21:35:11.000000000 +0000 @@ -53,7 +53,8 @@ """ iat = getInvalidAuthType() self.assertRaises(strcred.InvalidAuthType, strcred.makeChecker, iat) - self.assertRaises(strcred.InvalidAuthType, strcred.findCheckerFactory, iat) + self.assertRaises( + strcred.InvalidAuthType, strcred.findCheckerFactory, iat) def test_invalidAuthType(self): @@ -62,7 +63,8 @@ """ iat = getInvalidAuthType() self.assertRaises(strcred.InvalidAuthType, strcred.makeChecker, iat) - self.assertRaises(strcred.InvalidAuthType, strcred.findCheckerFactory, iat) + self.assertRaises( + strcred.InvalidAuthType, strcred.findCheckerFactory, iat) @@ -337,6 +339,32 @@ +class TestSSHChecker(unittest.TestCase): + """ + Tests for the --auth=sshkey:... checker. The majority of the tests for the + ssh public key database checker are in + L{twisted.conch.test.test_checkers.SSHPublicKeyDatabaseTestCase}. + """ + + try: + import Crypto + import pyasn1 + except ImportError: + skip = "PyCrypto is not available" + + + def test_isChecker(self): + """ + Verifies that strcred.makeChecker('sshkey') returns an object + that implements the L{ICredentialsChecker} interface. + """ + sshChecker = strcred.makeChecker('sshkey') + self.assertTrue(checkers.ICredentialsChecker.providedBy(sshChecker)) + self.assertIn( + credentials.ISSHPrivateKey, sshChecker.credentialInterfaces) + + + class DummyOptions(usage.Options, strcred.AuthOptionMixin): """ Simple options for testing L{strcred.AuthOptionMixin}. @@ -502,7 +530,8 @@ self.filename = self.mktemp() file(self.filename, 'w').write('admin:asdf\nalice:foo\n') self.goodChecker = checkers.FilePasswordDB(self.filename) - self.badChecker = checkers.FilePasswordDB(self.filename, hash=self._hash) + self.badChecker = checkers.FilePasswordDB( + self.filename, hash=self._hash) self.anonChecker = checkers.AllowAnonymousAccess() @@ -523,7 +552,8 @@ self.assertFalse( options.supportsInterface(credentials.IAnonymous)) self.assertRaises( - strcred.UnsupportedInterfaces, options.addChecker, self.anonChecker) + strcred.UnsupportedInterfaces, options.addChecker, + self.anonChecker) def test_supportsAllInterfaces(self): @@ -559,7 +589,8 @@ options.addChecker(self.goodChecker) iface = options.supportedInterfaces[0] # Test that we did get IUsernamePassword - self.assertIdentical(options['credInterfaces'][iface][0], self.goodChecker) + self.assertIdentical( + options['credInterfaces'][iface][0], self.goodChecker) self.assertIdentical(options['credCheckers'][0], self.goodChecker) # Test that we didn't get IUsernameHashedPassword self.assertEqual(len(options['credInterfaces'][iface]), 1) @@ -624,4 +655,3 @@ self.assertRaises(SystemExit, options.parseOptions, ['--help-auth-type', 'anonymous']) self.assertIn(strcred.notSupportedWarning, newStdout.getvalue()) - diff -Nru twisted-12.0.0/twisted/test/test_strerror.py twisted-12.2.0/twisted/test/test_strerror.py --- twisted-12.0.0/twisted/test/test_strerror.py 2011-11-07 04:58:37.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_strerror.py 2012-02-05 14:13:05.000000000 +0000 @@ -124,7 +124,7 @@ errorTab[self.probeErrorCode]) if platform.getType() != "win32": - test_fromEnvironment.skip = "This error lookup only works on Windows" + test_fromEnvironment.skip = "Test will run only on Windows." def test_correctLookups(self): @@ -148,4 +148,4 @@ self.assertIn(formatError(ECONNABORTED), acceptable) if platform.getType() != "win32": - test_correctLookups.skip = "This error lookup only works on Windows" + test_correctLookups.skip = "Test will run only on Windows." diff -Nru twisted-12.0.0/twisted/test/test_tcp.py twisted-12.2.0/twisted/test/test_tcp.py --- twisted-12.0.0/twisted/test/test_tcp.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_tcp.py 2012-03-27 12:27:04.000000000 +0000 @@ -602,6 +602,10 @@ started = 0 stopped = 0 + def __init__(self, *a, **kw): + MyClientFactory.__init__(self, *a, **kw) + self.whenStopped = defer.Deferred() + def startFactory(self): if self.started or self.stopped: raise RuntimeError @@ -611,6 +615,7 @@ if not self.started or self.stopped: raise RuntimeError self.stopped = 1 + self.whenStopped.callback(True) class FactoryTestCase(unittest.TestCase): @@ -677,99 +682,6 @@ -class ConnectorTestCase(unittest.TestCase): - - def test_connectorIdentity(self): - """ - L{IReactorTCP.connectTCP} returns an object which provides - L{IConnector}. The destination of the connector is the address which - was passed to C{connectTCP}. The same connector object is passed to - the factory's C{startedConnecting} method as to the factory's - C{clientConnectionLost} method. - """ - serverFactory = ClosingFactory() - tcpPort = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - serverFactory.port = tcpPort - self.addCleanup(serverFactory.cleanUp) - portNumber = tcpPort.getHost().port - - seenConnectors = [] - seenFailures = [] - - clientFactory = ClientStartStopFactory() - clientFactory.clientConnectionLost = ( - lambda connector, reason: (seenConnectors.append(connector), - seenFailures.append(reason))) - clientFactory.startedConnecting = seenConnectors.append - - connector = reactor.connectTCP("127.0.0.1", portNumber, clientFactory) - self.assertTrue(interfaces.IConnector.providedBy(connector)) - dest = connector.getDestination() - self.assertEqual(dest.type, "TCP") - self.assertEqual(dest.host, "127.0.0.1") - self.assertEqual(dest.port, portNumber) - - d = loopUntil(lambda: clientFactory.stopped) - def clientFactoryStopped(ignored): - seenFailures[0].trap(error.ConnectionDone) - self.assertEqual(seenConnectors, [connector, connector]) - d.addCallback(clientFactoryStopped) - return d - - - def test_userFail(self): - """ - Calling L{IConnector.stopConnecting} in C{Factory.startedConnecting} - results in C{Factory.clientConnectionFailed} being called with - L{error.UserError} as the reason. - """ - serverFactory = MyServerFactory() - tcpPort = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - self.addCleanup(tcpPort.stopListening) - portNumber = tcpPort.getHost().port - - def startedConnecting(connector): - connector.stopConnecting() - - clientFactory = ClientStartStopFactory() - clientFactory.startedConnecting = startedConnecting - reactor.connectTCP("127.0.0.1", portNumber, clientFactory) - - d = loopUntil(lambda: clientFactory.stopped) - def check(ignored): - self.assertEqual(clientFactory.failed, 1) - clientFactory.reason.trap(error.UserError) - return d.addCallback(check) - - - def test_reconnect(self): - """ - Calling L{IConnector.connect} in C{Factory.clientConnectionLost} causes - a new connection attempt to be made. - """ - serverFactory = ClosingFactory() - tcpPort = reactor.listenTCP(0, serverFactory, interface="127.0.0.1") - serverFactory.port = tcpPort - self.addCleanup(serverFactory.cleanUp) - portNumber = tcpPort.getHost().port - - clientFactory = MyClientFactory() - - def clientConnectionLost(connector, reason): - connector.connect() - clientFactory.clientConnectionLost = clientConnectionLost - reactor.connectTCP("127.0.0.1", portNumber, clientFactory) - - d = loopUntil(lambda: clientFactory.failed) - def reconnectFailed(ignored): - p = clientFactory.protocol - self.assertEqual((p.made, p.closed), (1, 1)) - clientFactory.reason.trap(error.ConnectionRefusedError) - self.assertEqual(clientFactory.stopped, 1) - return d.addCallback(reconnectFailed) - - - class CannotBindTestCase(unittest.TestCase): """ Tests for correct behavior when a reactor cannot bind to the required TCP diff -Nru twisted-12.0.0/twisted/test/test_text.py twisted-12.2.0/twisted/test/test_text.py --- twisted-12.0.0/twisted/test/test_text.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_text.py 2012-08-12 15:28:29.000000000 +0000 @@ -1,11 +1,14 @@ - # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +""" +Tests for L{twisted.python.text}. +""" + +from cStringIO import StringIO from twisted.trial import unittest from twisted.python import text -from cStringIO import StringIO sampleText = \ @@ -19,20 +22,21 @@ -- Auguste Comte, Philosophie Positive, Paris, 1838 """ -lineWidth = 72 - -def set_lineWidth(n): - global lineWidth - lineWidth = n class WrapTest(unittest.TestCase): + """ + Tests for L{text.greedyWrap}. + """ def setUp(self): + self.lineWidth = 72 self.sampleSplitText = sampleText.split() + self.output = text.wordWrap(sampleText, self.lineWidth) - self.output = text.wordWrap(sampleText, lineWidth) def test_wordCount(self): - """Compare the number of words.""" + """ + Compare the number of words. + """ words = [] for line in self.output: words.extend(line.split()) @@ -41,9 +45,11 @@ self.assertEqual(wordCount, sampleTextWordCount) - def test_wordMatch(self): - """Compare the lists of words.""" + def test_wordMatch(self): + """ + Compare the lists of words. + """ words = [] for line in self.output: words.extend(line.split()) @@ -52,28 +58,107 @@ # rather too long lists. self.failUnless(self.sampleSplitText == words) + def test_lineLength(self): - """Check the length of the lines.""" + """ + Check the length of the lines. + """ failures = [] for line in self.output: - if not len(line) <= lineWidth: + if not len(line) <= self.lineWidth: failures.append(len(line)) if failures: self.fail("%d of %d lines were too long.\n" "%d < %s" % (len(failures), len(self.output), - lineWidth, failures)) + self.lineWidth, failures)) + def test_doubleNewline(self): + """ + Allow paragraphs delimited by two \ns. + """ + sampleText = "et\n\nphone\nhome." + result = text.wordWrap(sampleText, self.lineWidth) + self.assertEqual(result, ["et", "", "phone home.", ""]) + + + +class LineTest(unittest.TestCase): + """ + Tests for L{isMultiline} and L{endsInNewline}. + """ + def test_isMultiline(self): + """ + L{text.isMultiline} returns C{True} if the string has a newline in it. + """ + s = 'This code\n "breaks."' + m = text.isMultiline(s) + self.assertTrue(m) + + s = 'This code does not "break."' + m = text.isMultiline(s) + self.assertFalse(m) + + + def test_endsInNewline(self): + """ + L{text.endsInNewline} returns C{True} if the string ends in a newline. + """ + s = 'newline\n' + m = text.endsInNewline(s) + self.assertTrue(m) + + s = 'oldline' + m = text.endsInNewline(s) + self.assertFalse(m) -class SplitTest(unittest.TestCase): - """Tests for text.splitQuoted()""" + +class StringyStringTest(unittest.TestCase): + """ + Tests for L{text.stringyString}. + """ + def test_tuple(self): + """ + Tuple elements are displayed on separate lines. + """ + s = ('a', 'b') + m = text.stringyString(s) + self.assertEqual(m, '(a,\n b,)\n') + + + def test_dict(self): + """ + Dicts elements are displayed using C{str()}. + """ + s = {'a': 0} + m = text.stringyString(s) + self.assertEqual(m, '{a: 0}') + + + def test_list(self): + """ + List elements are displayed on separate lines using C{str()}. + """ + s = ['a', 'b'] + m = text.stringyString(s) + self.assertEqual(m, '[a,\n b,]\n') + + + +class SplitTest(unittest.TestCase): + """ + Tests for L{text.splitQuoted}. + """ def test_oneWord(self): - """Splitting strings with one-word phrases.""" + """ + Splitting strings with one-word phrases. + """ s = 'This code "works."' r = text.splitQuoted(s) self.assertEqual(['This', 'code', 'works.'], r) + def test_multiWord(self): s = 'The "hairy monkey" likes pie.' r = text.splitQuoted(s) @@ -92,6 +177,8 @@ # r = text.splitQuoted(s) # self.assertEqual(["One Phrase"], r) + + class StrFileTest(unittest.TestCase): def setUp(self): self.io = StringIO("this is a test string") @@ -153,26 +240,3 @@ def test_insensitive(self): self.assertEqual(True, text.strFile("ThIs is A test STRING", self.io, False)) - - -class DeprecationTest(unittest.TestCase): - """ - Tests for deprecations in L{twisted.python.text} - """ - - def test_docstringLStrip(self): - """ - L{docstringLStrip} is deprecated as of 10.2.0 - """ - text.docstringLStrip("") - warningsShown = self.flushWarnings([self.test_docstringLStrip]) - self.assertEqual(1, len(warningsShown)) - self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEqual(warningsShown[0]['message'], - "twisted.python.text.docstringLStrip was " - "deprecated in Twisted 10.2.0: Please use " - "inspect.getdoc instead.") - - - -testCases = [WrapTest, SplitTest, StrFileTest] diff -Nru twisted-12.0.0/twisted/test/test_threadpool.py twisted-12.2.0/twisted/test/test_threadpool.py --- twisted-12.0.0/twisted/test/test_threadpool.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_threadpool.py 2012-02-11 11:29:31.000000000 +0000 @@ -7,7 +7,7 @@ import pickle, time, weakref, gc, threading -from twisted.trial import unittest, util +from twisted.trial import unittest from twisted.python import threadpool, threadable, failure, context from twisted.internet import reactor from twisted.internet.defer import Deferred @@ -249,19 +249,6 @@ (actor.failures,)) - def test_dispatch(self): - """ - Call C{_threadpoolTest} with C{dispatch}. - """ - return self._threadpoolTest( - lambda tp, actor: tp.dispatch(actor, actor.run)) - - test_dispatch.suppress = [util.suppress( - message="dispatch\(\) is deprecated since Twisted 8.0, " - "use callInThread\(\) instead", - category=DeprecationWarning)] - - def test_callInThread(self): """ Call C{_threadpoolTest} with C{callInThread}. @@ -471,44 +458,6 @@ tp.stop() - def test_dispatchDeprecation(self): - """ - Test for the deprecation of the dispatch method. - """ - tp = threadpool.ThreadPool() - tp.start() - self.addCleanup(tp.stop) - - def cb(): - return tp.dispatch(None, lambda: None) - - self.assertWarns(DeprecationWarning, - "dispatch() is deprecated since Twisted 8.0, " - "use callInThread() instead", - __file__, cb) - - - def test_dispatchWithCallbackDeprecation(self): - """ - Test for the deprecation of the dispatchWithCallback method. - """ - tp = threadpool.ThreadPool() - tp.start() - self.addCleanup(tp.stop) - - def cb(): - return tp.dispatchWithCallback( - None, - lambda x: None, - lambda x: None, - lambda: None) - - self.assertWarns(DeprecationWarning, - "dispatchWithCallback() is deprecated since Twisted 8.0, " - "use twisted.internet.threads.deferToThread() instead.", - __file__, cb) - - class RaceConditionTestCase(unittest.TestCase): def setUp(self): @@ -575,25 +524,3 @@ loopDeferred.addCallback(cbLoop) submit(10) return loopDeferred - - - -class ThreadSafeListDeprecationTestCase(unittest.TestCase): - """ - Test deprecation of threadpool.ThreadSafeList in twisted.python.threadpool - """ - - def test_threadSafeList(self): - """ - Test deprecation of L{threadpool.ThreadSafeList}. - """ - threadpool.ThreadSafeList() - - warningsShown = self.flushWarnings([self.test_threadSafeList]) - self.assertEqual(len(warningsShown), 1) - self.assertIdentical(warningsShown[0]['category'], DeprecationWarning) - self.assertEqual( - warningsShown[0]['message'], - "twisted.python.threadpool.ThreadSafeList was deprecated in " - "Twisted 10.1.0: This was an internal implementation detail of " - "support for Jython 2.1, which is now obsolete.") diff -Nru twisted-12.0.0/twisted/test/test_threads.py twisted-12.2.0/twisted/test/test_threads.py --- twisted-12.0.0/twisted/test/test_threads.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_threads.py 2012-06-07 14:09:07.000000000 +0000 @@ -275,7 +275,7 @@ # alas, this test appears to flunk the default reactor too d = threads.deferToThread(lambda: None) - d.addCallback(lambda ign: threads.deferToThread(lambda: 1/0)) + d.addCallback(lambda ign: threads.deferToThread(lambda: 1//0)) return self.assertFailure(d, ZeroDivisionError) diff -Nru twisted-12.0.0/twisted/test/test_timehelpers.py twisted-12.2.0/twisted/test/test_timehelpers.py --- twisted-12.0.0/twisted/test/test_timehelpers.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_timehelpers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Tests for the deprecated L{twisted.test.time_helpers} module. -""" - -import sys - -from twisted.trial.unittest import TestCase - - -class TimeHelpersTests(TestCase): - """ - A test for the deprecation of the module. - """ - def test_deprecated(self): - """ - Importing L{twisted.test.time_helpers} causes a deprecation warning - to be emitted. - """ - # Make sure we're really importing it - sys.modules.pop('twisted.test.time_helpers', None) - import twisted.test.time_helpers - warnings = self.flushWarnings( - offendingFunctions=[self.test_deprecated]) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual( - warnings[0]['message'], - "twisted.test.time_helpers is deprecated since Twisted 10.0. " - "See twisted.internet.task.Clock instead.") diff -Nru twisted-12.0.0/twisted/test/test_twistd.py twisted-12.2.0/twisted/test/test_twistd.py --- twisted-12.0.0/twisted/test/test_twistd.py 2011-10-04 20:16:52.000000000 +0000 +++ twisted-12.2.0/twisted/test/test_twistd.py 2012-03-12 07:01:11.000000000 +0000 @@ -23,6 +23,7 @@ from zope.interface.verify import verifyObject from twisted.trial import unittest +from twisted.test.test_process import MockOS from twisted import plugin from twisted.application.service import IServiceMaker @@ -34,6 +35,7 @@ from twisted.python.versions import Version from twisted.python.components import Componentized from twisted.internet.defer import Deferred +from twisted.internet.interfaces import IReactorDaemonize from twisted.python.fakepwd import UserDatabase try: @@ -616,7 +618,7 @@ self.runner = UnixApplicationRunner({}) - def daemonize(self): + def daemonize(self, reactor, os): """ Indicate that daemonization has happened and change the PID so that the value written to the pidfile can be tested in the daemonization case. @@ -806,6 +808,76 @@ +class FakeNonDaemonizingReactor(object): + """ + A dummy reactor, providing C{beforeDaemonize} and C{afterDaemonize} methods, + but not announcing this, and logging whether the methods have been called. + + @ivar _beforeDaemonizeCalled: if C{beforeDaemonize} has been called or not. + @type _beforeDaemonizeCalled: C{bool} + @ivar _afterDaemonizeCalled: if C{afterDaemonize} has been called or not. + @type _afterDaemonizeCalled: C{bool} + """ + + def __init__(self): + self._beforeDaemonizeCalled = False + self._afterDaemonizeCalled = False + + def beforeDaemonize(self): + self._beforeDaemonizeCalled = True + + def afterDaemonize(self): + self._afterDaemonizeCalled = True + + + +class FakeDaemonizingReactor(FakeNonDaemonizingReactor): + """ + A dummy reactor, providing C{beforeDaemonize} and C{afterDaemonize} methods, + announcing this, and logging whether the methods have been called. + """ + + implements(IReactorDaemonize) + + + +class ReactorDaemonizationTests(unittest.TestCase): + """ + Tests for L{_twistd_unix.daemonize} and L{IReactorDaemonize}. + """ + if _twistd_unix is None: + skip = "twistd unix not available" + + + def test_daemonizationHooksCalled(self): + """ + L{_twistd_unix.daemonize} indeed calls + L{IReactorDaemonize.beforeDaemonize} and + L{IReactorDaemonize.afterDaemonize} if the reactor implements + L{IReactorDaemonize}. + """ + reactor = FakeDaemonizingReactor() + os = MockOS() + _twistd_unix.daemonize(reactor, os) + self.assertTrue(reactor._beforeDaemonizeCalled) + self.assertTrue(reactor._afterDaemonizeCalled) + + + def test_daemonizationHooksNotCalled(self): + """ + L{_twistd_unix.daemonize} does NOT call + L{IReactorDaemonize.beforeDaemonize} or + L{IReactorDaemonize.afterDaemonize} if the reactor does NOT + implement L{IReactorDaemonize}. + """ + reactor = FakeNonDaemonizingReactor() + os = MockOS() + _twistd_unix.daemonize(reactor, os) + self.assertFalse(reactor._beforeDaemonizeCalled) + self.assertFalse(reactor._afterDaemonizeCalled) + + + class DummyReactor(object): """ A dummy reactor, only providing a C{run} method and checking that it @@ -1475,20 +1547,3 @@ - -class DeprecationTests(unittest.TestCase): - """ - Tests for deprecated features. - """ - - def test_initialLog(self): - """ - L{app.initialLog} is deprecated. - """ - logs = [] - log.addObserver(logs.append) - self.addCleanup(log.removeObserver, logs.append) - self.callDeprecated(Version("Twisted", 8, 2, 0), app.initialLog) - self.assertEqual(len(logs), 2) - self.assertIn("starting up", logs[0]["message"][0]) - self.assertIn("reactor class", logs[1]["message"][0]) diff -Nru twisted-12.0.0/twisted/test/time_helpers.py twisted-12.2.0/twisted/test/time_helpers.py --- twisted-12.0.0/twisted/test/time_helpers.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/test/time_helpers.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -# Copyright (c) Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Helper class to writing deterministic time-based unit tests. - -Do not use this module. It is a lie. See L{twisted.internet.task.Clock} -instead. -""" - -import warnings -warnings.warn( - "twisted.test.time_helpers is deprecated since Twisted 10.0. " - "See twisted.internet.task.Clock instead.", - category=DeprecationWarning, stacklevel=2) - - -class Clock(object): - """ - A utility for monkey-patches various parts of Twisted to use a - simulated timing mechanism. DO NOT use this class. Use - L{twisted.internet.task.Clock}. - """ - rightNow = 0.0 - - def __call__(self): - """ - Return the current simulated time. - """ - return self.rightNow - - def install(self): - """ - Monkeypatch L{twisted.internet.reactor.seconds} to use - L{__call__} as a time source - """ - # Violation is fun. - from twisted.internet import reactor - self.reactor_original = reactor.seconds - reactor.seconds = self - - def uninstall(self): - """ - Remove the monkeypatching of L{twisted.internet.reactor.seconds}. - """ - from twisted.internet import reactor - reactor.seconds = self.reactor_original - - def adjust(self, amount): - """ - Adjust the current simulated time upward by the given C{amount}. - - Note that this does not cause any scheduled calls to be run. - """ - self.rightNow += amount - - def pump(self, reactor, timings): - """ - Iterate the given C{reactor} with increments of time specified - by C{timings}. - - For each timing, the simulated time will be L{adjust}ed and - the reactor will be iterated twice. - """ - timings = list(timings) - timings.reverse() - self.adjust(timings.pop()) - while timings: - self.adjust(timings.pop()) - reactor.iterate() - reactor.iterate() - diff -Nru twisted-12.0.0/twisted/trial/reporter.py twisted-12.2.0/twisted/trial/reporter.py --- twisted-12.0.0/twisted/trial/reporter.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/trial/reporter.py 2012-08-17 13:50:10.000000000 +0000 @@ -472,7 +472,14 @@ def _trimFrames(self, frames): - # when a method fails synchronously, the stack looks like this: + # when a SynchronousTestCase method fails synchronously, the stack looks + # like this: + # [0]: SynchronousTestCase._run + # [1]: utils.runWithWarningsSuppressed + # [2:-2]: code in the test method which failed + # [-1]: unittst.fail + + # when a TestCase method fails synchronously, the stack looks like this: # [0]: defer.maybeDeferred() # [1]: utils.runWithWarningsSuppressed() # [2:-2]: code in the test method which failed @@ -486,8 +493,8 @@ # [-1]: unittest.fail # as a result, we want to trim either [maybeDeferred,runWWS] or - # [Deferred._runCallbacks] from the front, and trim the - # [unittest.fail] from the end. + # [Deferred._runCallbacks] or [SynchronousTestCase._run] from the front, + # and trim the [unittest.fail] from the end. # There is also another case, when the test method is badly defined and # contains extra arguments. @@ -497,15 +504,20 @@ if len(frames) < 2: return newFrames - first = newFrames[0] - second = newFrames[1] - if (first[0] == "maybeDeferred" - and os.path.splitext(os.path.basename(first[1]))[0] == 'defer' - and second[0] == "runWithWarningsSuppressed" - and os.path.splitext(os.path.basename(second[1]))[0] == 'utils'): + firstMethod = newFrames[0][0] + firstFile = os.path.splitext(os.path.basename(newFrames[0][1]))[0] + + secondMethod = newFrames[1][0] + secondFile = os.path.splitext(os.path.basename(newFrames[1][1]))[0] + + supp = ("runWithWarningsSuppressed", "utils") + syncCase = (("_run", "unittest"), supp) + asyncCase = (("maybeDeferred", "defer"), supp) + + twoFrames = ((firstMethod, firstFile), (secondMethod, secondFile)) + if twoFrames in [syncCase, asyncCase]: newFrames = newFrames[2:] - elif (first[0] == "_runCallbacks" - and os.path.splitext(os.path.basename(first[1]))[0] == 'defer'): + elif (firstMethod, firstFile) == ("_runCallbacks", "defer"): newFrames = newFrames[1:] if not newFrames: diff -Nru twisted-12.0.0/twisted/trial/runner.py twisted-12.2.0/twisted/trial/runner.py --- twisted-12.0.0/twisted/trial/runner.py 2011-10-02 14:12:39.000000000 +0000 +++ twisted-12.2.0/twisted/trial/runner.py 2012-08-03 11:10:08.000000000 +0000 @@ -11,7 +11,7 @@ __all__ = [ 'suiteVisit', 'TestSuite', - 'DestructiveTestSuite', 'DocTestCase', 'DryRunVisitor', + 'DestructiveTestSuite', 'DryRunVisitor', 'ErrorHolder', 'LoggedSuite', 'PyUnitTestCase', 'TestHolder', 'TestLoader', 'TrialRunner', 'TrialSuite', @@ -239,22 +239,6 @@ -class DocTestCase(PyUnitTestCase): - """ - DEPRECATED in Twisted 8.0. - """ - - def id(self): - """ - In Python 2.4, doctests have correct id() behaviour. In Python 2.3, - id() returns 'runit'. - - Here we override id() so that at least it will always contain the - fully qualified Python name of the doctest. - """ - return self._test.shortDescription() - - class TrialSuite(TestSuite): """ Suite to wrap around every single test in a C{trial} run. Used internally diff -Nru twisted-12.0.0/twisted/trial/test/detests.py twisted-12.2.0/twisted/trial/test/detests.py --- twisted-12.0.0/twisted/trial/test/detests.py 2006-02-11 09:35:56.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/detests.py 2012-05-31 17:58:56.000000000 +0000 @@ -1,4 +1,10 @@ -from __future__ import generators +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for Deferred handling by L{twisted.trial.unittest.TestCase}. +""" + from twisted.trial import unittest from twisted.internet import defer, threads, reactor @@ -18,7 +24,7 @@ class DeferredSetUpFail(unittest.TestCase): testCalled = False - + def setUp(self): return defer.fail(unittest.FailTest('i fail')) @@ -29,7 +35,7 @@ class DeferredSetUpCallbackFail(unittest.TestCase): testCalled = False - + def setUp(self): d = defer.succeed('value') d.addCallback(self._cb_setUpCalled) @@ -41,10 +47,10 @@ def test_ok(self): DeferredSetUpCallbackFail.testCalled = True - + class DeferredSetUpError(unittest.TestCase): testCalled = False - + def setUp(self): return defer.fail(RuntimeError('deliberate error')) @@ -54,7 +60,7 @@ class DeferredSetUpNeverFire(unittest.TestCase): testCalled = False - + def setUp(self): return defer.Deferred() @@ -64,7 +70,7 @@ class DeferredSetUpSkip(unittest.TestCase): testCalled = False - + def setUp(self): d = defer.succeed('value') d.addCallback(self._cb1) @@ -79,7 +85,7 @@ class DeferredTests(unittest.TestCase): touched = False - + def _cb_fail(self, reason): self.fail(reason) @@ -134,7 +140,7 @@ class TimeoutTests(unittest.TestCase): timedOut = None - + def test_pass(self): d = defer.Deferred() reactor.callLater(0, d.callback, 'hoorj!') @@ -159,7 +165,7 @@ return defer.Deferred() test_expectedFailure.timeout = 0.1 test_expectedFailure.todo = "i will get it right, eventually" - + def test_skip(self): return defer.Deferred() test_skip.timeout = 0.1 diff -Nru twisted-12.0.0/twisted/trial/test/erroneous.py twisted-12.2.0/twisted/trial/test/erroneous.py --- twisted-12.0.0/twisted/trial/test/erroneous.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/erroneous.py 2012-08-17 13:50:10.000000000 +0000 @@ -2,6 +2,16 @@ # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. +""" +Definitions of test cases with various interesting error-related behaviors, to +be used by test modules to exercise different features of trial's test runner. + +See the L{twisted.trial.test.test_tests} module docstring for details about how +this code is arranged. +""" + +from __future__ import division + from twisted.trial import unittest, util from twisted.internet import reactor, protocol, defer @@ -10,7 +20,8 @@ pass -class TestFailureInSetUp(unittest.TestCase): + +class FailureInSetUpMixin(object): def setUp(self): raise FoolishError, "I am a broken setUp method" @@ -18,7 +29,20 @@ pass -class TestFailureInTearDown(unittest.TestCase): + +class SynchronousTestFailureInSetUp( + FailureInSetUpMixin, unittest.SynchronousTestCase): + pass + + + +class AsynchronousTestFailureInSetUp( + FailureInSetUpMixin, unittest.TestCase): + pass + + + +class FailureInTearDownMixin(object): def tearDown(self): raise FoolishError, "I am a broken tearDown method" @@ -26,7 +50,20 @@ pass -class TestRegularFail(unittest.TestCase): + +class SynchronousTestFailureInTearDown( + FailureInTearDownMixin, unittest.SynchronousTestCase): + pass + + + +class AsynchronousTestFailureInTearDown( + FailureInTearDownMixin, unittest.TestCase): + pass + + + +class TestRegularFail(unittest.SynchronousTestCase): def test_fail(self): self.fail("I fail") @@ -47,7 +84,7 @@ -class ErrorTest(unittest.TestCase): +class ErrorTest(unittest.SynchronousTestCase): """ A test case which has a L{test_foo} which will raise an error. @@ -64,7 +101,7 @@ -class TestSkipTestCase(unittest.TestCase): +class TestSkipTestCase(unittest.SynchronousTestCase): pass TestSkipTestCase.skip = "skipping this test" diff -Nru twisted-12.0.0/twisted/trial/test/mockdoctest.py twisted-12.2.0/twisted/trial/test/mockdoctest.py --- twisted-12.0.0/twisted/trial/test/mockdoctest.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/mockdoctest.py 2012-06-07 14:09:07.000000000 +0000 @@ -3,7 +3,7 @@ # this module is a trivial class with doctests and a __test__ attribute # to test trial's doctest support with python2.4 - +from __future__ import division class Counter(object): """a simple counter object for testing trial's doctest support diff -Nru twisted-12.0.0/twisted/trial/test/skipping.py twisted-12.2.0/twisted/trial/test/skipping.py --- twisted-12.0.0/twisted/trial/test/skipping.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/skipping.py 2012-08-17 13:50:10.000000000 +0000 @@ -0,0 +1,268 @@ +# -*- test-case-name: twisted.trial.test.test_tests -*- +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Definitions of test cases with various interesting behaviors, to be used by +L{twisted.trial.test.test_tests} and other test modules to exercise different +features of trial's test runner. + +See the L{twisted.trial.test.test_tests} module docstring for details about how +this code is arranged. +""" + +from twisted.trial.unittest import ( + SynchronousTestCase, TestCase, SkipTest, FailTest) + + +class SkippingMixin(object): + def test_skip1(self): + raise SkipTest('skip1') + + def test_skip2(self): + raise RuntimeError("I should not get raised") + test_skip2.skip = 'skip2' + + def test_skip3(self): + self.fail('I should not fail') + test_skip3.skip = 'skip3' + + + +class SynchronousSkipping(SkippingMixin, SynchronousTestCase): + pass + + + +class AsynchronousSkipping(SkippingMixin, TestCase): + pass + + + +class SkippingSetUpMixin(object): + def setUp(self): + raise SkipTest('skipSetUp') + + def test_1(self): + pass + + def test_2(self): + pass + + +class SynchronousSkippingSetUp(SkippingSetUpMixin, SynchronousTestCase): + pass + + + +class AsynchronousSkippingSetUp(SkippingSetUpMixin, TestCase): + pass + + + +class DeprecatedReasonlessSkipMixin(object): + def test_1(self): + raise SkipTest() + + + +class SynchronousDeprecatedReasonlessSkip( + DeprecatedReasonlessSkipMixin, SynchronousTestCase): + pass + + + +class AsynchronousDeprecatedReasonlessSkip( + DeprecatedReasonlessSkipMixin, TestCase): + pass + + + +class SkippedClassMixin(object): + skip = 'class' + def setUp(self): + self.__class__._setUpRan = True + def test_skip1(self): + raise SkipTest('skip1') + def test_skip2(self): + raise RuntimeError("Ought to skip me") + test_skip2.skip = 'skip2' + def test_skip3(self): + pass + def test_skip4(self): + raise RuntimeError("Skip me too") + + + +class SynchronousSkippedClass(SkippedClassMixin, SynchronousTestCase): + pass + + + +class AsynchronousSkippedClass(SkippedClassMixin, TestCase): + pass + + + +class TodoMixin(object): + def test_todo1(self): + self.fail("deliberate failure") + test_todo1.todo = "todo1" + + def test_todo2(self): + raise RuntimeError("deliberate error") + test_todo2.todo = "todo2" + + def test_todo3(self): + """unexpected success""" + test_todo3.todo = 'todo3' + + + + +class SynchronousTodo(TodoMixin, SynchronousTestCase): + pass + + + +class AsynchronousTodo(TodoMixin, TestCase): + pass + + + +class SetUpTodoMixin(object): + def setUp(self): + raise RuntimeError("deliberate error") + + def test_todo1(self): + pass + test_todo1.todo = "setUp todo1" + + + +class SynchronousSetUpTodo(SetUpTodoMixin, SynchronousTestCase): + pass + + + +class AsynchronousSetUpTodo(SetUpTodoMixin, TestCase): + pass + + + +class TearDownTodoMixin(object): + def tearDown(self): + raise RuntimeError("deliberate error") + + def test_todo1(self): + pass + test_todo1.todo = "tearDown todo1" + + + +class SynchronousTearDownTodo(TearDownTodoMixin, SynchronousTestCase): + pass + + + +class AsynchronousTearDownTodo(TearDownTodoMixin, TestCase): + pass + + + +class TodoClassMixin(object): + todo = "class" + def test_todo1(self): + pass + test_todo1.todo = "method" + def test_todo2(self): + pass + def test_todo3(self): + self.fail("Deliberate Failure") + test_todo3.todo = "method" + def test_todo4(self): + self.fail("Deliberate Failure") + + + +class SynchronousTodoClass(TodoClassMixin, SynchronousTestCase): + pass + + + +class AsynchronousTodoClass(TodoClassMixin, TestCase): + pass + + + +class StrictTodoMixin(object): + def test_todo1(self): + raise RuntimeError("expected failure") + test_todo1.todo = (RuntimeError, "todo1") + + def test_todo2(self): + raise RuntimeError("expected failure") + test_todo2.todo = ((RuntimeError, OSError), "todo2") + + def test_todo3(self): + raise RuntimeError("we had no idea!") + test_todo3.todo = (OSError, "todo3") + + def test_todo4(self): + raise RuntimeError("we had no idea!") + test_todo4.todo = ((OSError, SyntaxError), "todo4") + + def test_todo5(self): + self.fail("deliberate failure") + test_todo5.todo = (FailTest, "todo5") + + def test_todo6(self): + self.fail("deliberate failure") + test_todo6.todo = (RuntimeError, "todo6") + + def test_todo7(self): + pass + test_todo7.todo = (RuntimeError, "todo7") + + + +class SynchronousStrictTodo(StrictTodoMixin, SynchronousTestCase): + pass + + + +class AsynchronousStrictTodo(StrictTodoMixin, TestCase): + pass + + + +class AddCleanupMixin(object): + def setUp(self): + self.log = ['setUp'] + + def brokenSetUp(self): + self.log = ['setUp'] + raise RuntimeError("Deliberate failure") + + def skippingSetUp(self): + self.log = ['setUp'] + raise SkipTest("Don't do this") + + def append(self, thing): + self.log.append(thing) + + def tearDown(self): + self.log.append('tearDown') + + def runTest(self): + self.log.append('runTest') + + + +class SynchronousAddCleanup(AddCleanupMixin, SynchronousTestCase): + pass + + + +class AsynchronousAddCleanup(AddCleanupMixin, TestCase): + pass diff -Nru twisted-12.0.0/twisted/trial/test/suppression.py twisted-12.2.0/twisted/trial/test/suppression.py --- twisted-12.0.0/twisted/trial/test/suppression.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/suppression.py 2012-08-17 13:50:10.000000000 +0000 @@ -5,6 +5,9 @@ """ Test cases used to make sure that warning supression works at the module, method, and class levels. + +See the L{twisted.trial.test.test_tests} module docstring for details about how +this code is arranged. """ import warnings @@ -33,7 +36,9 @@ warnings.warn(MODULE_WARNING_MSG, ModuleWarning) -class TestSuppression(unittest.TestCase, EmitMixin): +class SuppressionMixin(EmitMixin): + suppress = [util.suppress(message=CLASS_WARNING_MSG)] + def testSuppressMethod(self): self._emit() testSuppressMethod.suppress = [util.suppress(message=METHOD_WARNING_MSG)] @@ -45,13 +50,63 @@ self._emit() testOverrideSuppressClass.suppress = [] -TestSuppression.suppress = [util.suppress(message=CLASS_WARNING_MSG)] -class TestSuppression2(unittest.TestCase, EmitMixin): +class SynchronousTestSuppression(SuppressionMixin, unittest.SynchronousTestCase): + pass + + + +class AsynchronousTestSuppression(SuppressionMixin, unittest.TestCase): + pass + + + +class SetUpSuppressionMixin(object): + def setUp(self): + self._emit() + + + +class SynchronousTestSetUpSuppression(SetUpSuppressionMixin, SynchronousTestSuppression): + pass + + + +class AsynchronousTestSetUpSuppression(SetUpSuppressionMixin, AsynchronousTestSuppression): + pass + + + +class TearDownSuppressionMixin(object): + def tearDown(self): + self._emit() + + + +class SynchronousTestTearDownSuppression(TearDownSuppressionMixin, SynchronousTestSuppression): + pass + + + +class AsynchronousTestTearDownSuppression(TearDownSuppressionMixin, AsynchronousTestSuppression): + pass + + + +class TestSuppression2Mixin(EmitMixin): def testSuppressModule(self): self._emit() -suppress = [util.suppress(message=MODULE_WARNING_MSG)] +class SynchronousTestSuppression2(TestSuppression2Mixin, unittest.SynchronousTestCase): + pass + + + +class AsynchronousTestSuppression2(TestSuppression2Mixin, unittest.TestCase): + pass + + +suppress = [util.suppress(message=MODULE_WARNING_MSG)] diff -Nru twisted-12.0.0/twisted/trial/test/test_assertions.py twisted-12.2.0/twisted/trial/test/test_assertions.py --- twisted-12.0.0/twisted/trial/test/test_assertions.py 2011-10-17 19:26:52.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_assertions.py 2012-08-17 13:50:10.000000000 +0000 @@ -1,12 +1,22 @@ -# Copyright (c) 2001-2011 Twisted Matrix Laboratories. -# See LICENSE for details +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. """ -Tests for assertions provided by L{twisted.trial.unittest.TestCase}. +Tests for assertions provided by C{SynchronousTestCase} and C{TestCase}, +provided by L{twisted.trial.unittest}. + +L{TestFailureTests} demonstrates that L{SynchronousTestCase.fail} works, so that +is the only method on C{twisted.trial.unittest.SynchronousTestCase} that is +initially assumed to work. The test classes are arranged so that the methods +demonstrated to work earlier in the file are used by those later in the file +(even though the runner will probably not run the tests in this order). """ +from __future__ import division + import warnings from pprint import pformat +import unittest as pyunit from twisted.python import reflect, failure from twisted.python.deprecate import deprecated, getVersionString @@ -27,63 +37,222 @@ return self.name[0] == other.name[0] -class TestAssertions(unittest.TestCase): +class TestFailureTests(pyunit.TestCase): """ - Tests for TestCase's assertion methods. That is, failUnless*, - failIf*, assert*. - - Note: As of 11.2, assertEqual is preferred over the failUnlessEqual(s) - variants. Tests have been modified to reflect this preference. + Tests for the most basic functionality of L{SynchronousTestCase}, for + failing tests. - This is pretty paranoid. Still, a certain paranoia is healthy if you - are testing a unit testing framework. + This class contains tests to demonstrate that L{SynchronousTestCase.fail} + can be used to fail a test, and that that failure is reflected in the test + result object. This should be sufficient functionality so that further + tests can be built on L{SynchronousTestCase} instead of + L{unittest.TestCase}. This depends on L{unittest.TestCase} working. """ - - class FailingTest(unittest.TestCase): + class FailingTest(unittest.SynchronousTestCase): def test_fails(self): - raise self.failureException() + self.fail("This test fails.") + + + def setUp(self): + """ + Load a suite of one test which can be used to exercise the failure + handling behavior. + """ + components = [ + __name__, self.__class__.__name__, self.FailingTest.__name__] + self.loader = pyunit.TestLoader() + self.suite = self.loader.loadTestsFromName(".".join(components)) + self.test = list(self.suite)[0] + - def testFail(self): + def test_fail(self): + """ + L{SynchronousTestCase.fail} raises + L{SynchronousTestCase.failureException} with the given argument. + """ try: - self.fail("failed") - except self.failureException, e: - if not str(e) == 'failed': - raise self.failureException("Exception had msg %s instead of %s" - % str(e), 'failed') + self.test.fail("failed") + except self.test.failureException as result: + self.assertEqual("failed", str(result)) else: - raise self.failureException("Call to self.fail() didn't fail test") + self.fail( + "SynchronousTestCase.fail method did not raise " + "SynchronousTestCase.failureException") - def test_failingException_fails(self): - test = runner.TestLoader().loadClass(TestAssertions.FailingTest) - result = reporter.TestResult() - test.run(result) + + def test_failingExceptionFails(self): + """ + When a test method raises L{SynchronousTestCase.failureException}, the test is + marked as having failed on the L{TestResult}. + """ + result = pyunit.TestResult() + self.suite.run(result) self.failIf(result.wasSuccessful()) self.assertEqual(result.errors, []) self.assertEqual(len(result.failures), 1) + self.assertEqual(result.failures[0][0], self.test) + + + +class AssertFalseTests(unittest.SynchronousTestCase): + """ + Tests for L{SynchronousTestCase}'s C{assertFalse} and C{failIf} assertion + methods. + + This is pretty paranoid. Still, a certain paranoia is healthy if you + are testing a unit testing framework. + + @note: As of 11.2, C{assertFalse} is preferred over C{failIf}. + """ + def _assertFalseFalse(self, method): + """ + Perform the positive case test for C{failIf} or C{assertFalse}. - def test_failIf(self): + @param method: The test method to test. + """ for notTrue in [0, 0.0, False, None, (), []]: - self.failIf(notTrue, "failed on %r" % (notTrue,)) + result = method(notTrue, "failed on %r" % (notTrue,)) + if result != notTrue: + self.fail("Did not return argument %r" % (notTrue,)) + + + def _assertFalseTrue(self, method): + """ + Perform the negative case test for C{failIf} or C{assertFalse}. + + @param method: The test method to test. + """ for true in [1, True, 'cat', [1,2], (3,4)]: try: - self.failIf(true, "failed on %r" % (true,)) + method(true, "failed on %r" % (true,)) except self.failureException, e: - self.assertEqual(str(e), "failed on %r" % (true,)) + if str(e) != "failed on %r" % (true,): + self.fail("Raised incorrect exception on %r: %r" % (true, e)) else: self.fail("Call to failIf(%r) didn't fail" % (true,)) - def test_failUnless(self): + + def test_failIfFalse(self): + """ + L{SynchronousTestCase.failIf} returns its argument if its argument is + not considered true. + """ + self._assertFalseFalse(self.failIf) + + + def test_assertFalseFalse(self): + """ + L{SynchronousTestCase.assertFalse} returns its argument if its argument + is not considered true. + """ + self._assertFalseFalse(self.assertFalse) + + + def test_failIfTrue(self): + """ + L{SynchronousTestCase.failIf} raises + L{SynchronousTestCase.failureException} if its argument is considered + true. + """ + self._assertFalseTrue(self.failIf) + + + def test_assertFalseTrue(self): + """ + L{SynchronousTestCase.assertFalse} raises + L{SynchronousTestCase.failureException} if its argument is considered + true. + """ + self._assertFalseTrue(self.assertFalse) + + + +class AssertTrueTests(unittest.SynchronousTestCase): + """ + Tests for L{SynchronousTestCase}'s C{assertTrue} and C{failUnless} assertion + methods. + + This is pretty paranoid. Still, a certain paranoia is healthy if you + are testing a unit testing framework. + + @note: As of 11.2, C{assertTrue} is preferred over C{failUnless}. + """ + def _assertTrueFalse(self, method): + """ + Perform the negative case test for C{assertTrue} and C{failUnless}. + + @param method: The test method to test. + """ for notTrue in [0, 0.0, False, None, (), []]: try: - self.failUnless(notTrue, "failed on %r" % (notTrue,)) + method(notTrue, "failed on %r" % (notTrue,)) except self.failureException, e: - self.assertEqual(str(e), "failed on %r" % (notTrue,)) + if str(e) != "failed on %r" % (notTrue,): + self.fail( + "Raised incorrect exception on %r: %r" % (notTrue, e)) else: - self.fail("Call to failUnless(%r) didn't fail" % (notTrue,)) + self.fail( + "Call to %s(%r) didn't fail" % (method.__name__, notTrue,)) + + + def _assertTrueTrue(self, method): + """ + Perform the positive case test for C{assertTrue} and C{failUnless}. + + @param method: The test method to test. + """ for true in [1, True, 'cat', [1,2], (3,4)]: - self.failUnless(true, "failed on %r" % (true,)) + result = method(true, "failed on %r" % (true,)) + if result != true: + self.fail("Did not return argument %r" % (true,)) + def test_assertTrueFalse(self): + """ + L{SynchronousTestCase.assertTrue} raises + L{SynchronousTestCase.failureException} if its argument is not + considered true. + """ + self._assertTrueFalse(self.assertTrue) + + + def test_failUnlessFalse(self): + """ + L{SynchronousTestCase.failUnless} raises + L{SynchronousTestCase.failureException} if its argument is not + considered true. + """ + self._assertTrueFalse(self.failUnless) + + + def test_assertTrueTrue(self): + """ + L{SynchronousTestCase.assertTrue} returns its argument if its argument + is considered true. + """ + self._assertTrueTrue(self.assertTrue) + + + def test_failUnlessTrue(self): + """ + L{SynchronousTestCase.failUnless} returns its argument if its argument + is considered true. + """ + self._assertTrueTrue(self.failUnless) + + + +class TestSynchronousAssertions(unittest.SynchronousTestCase): + """ + Tests for L{SynchronousTestCase}'s assertion methods. That is, failUnless*, + failIf*, assert* (not covered by other more specific test classes). + + Note: As of 11.2, assertEqual is preferred over the failUnlessEqual(s) + variants. Tests have been modified to reflect this preference. + + This is pretty paranoid. Still, a certain paranoia is healthy if you are + testing a unit testing framework. + """ def _testEqualPair(self, first, second): x = self.assertEqual(first, second) if x != first: @@ -225,6 +394,28 @@ # test when __ne__ is not defined self.failIfEqual(x, z, "__ne__ not defined, so not equal") + + def test_failIfIdenticalPositive(self): + """ + C{failIfIdentical} returns its first argument if its first and second + arguments are not the same object. + """ + x = object() + y = object() + result = self.failIfIdentical(x, y) + self.assertEqual(x, result) + + + def test_failIfIdenticalNegative(self): + """ + C{failIfIdentical} raises C{failureException} if its first and second + arguments are the same object. + """ + x = object() + self.failUnlessRaises(self.failureException, + self.failIfIdentical, x, x) + + def test_failUnlessIdentical(self): x, y, z = [1], [1], [2] ret = self.failUnlessIdentical(x, x) @@ -296,10 +487,123 @@ self.failUnlessRaises(self.failureException, self.failIfSubstring, x, z) + + def test_assertIsInstance(self): + """ + Test a true condition of assertIsInstance. + """ + A = type('A', (object,), {}) + a = A() + self.assertIsInstance(a, A) + + + def test_assertIsInstanceMultipleClasses(self): + """ + Test a true condition of assertIsInstance with multiple classes. + """ + A = type('A', (object,), {}) + B = type('B', (object,), {}) + a = A() + self.assertIsInstance(a, (A, B)) + + + def test_assertIsInstanceError(self): + """ + Test an error with assertIsInstance. + """ + A = type('A', (object,), {}) + B = type('B', (object,), {}) + a = A() + self.assertRaises(self.failureException, self.assertIsInstance, a, B) + + + def test_assertIsInstanceErrorMultipleClasses(self): + """ + Test an error with assertIsInstance and multiple classes. + """ + A = type('A', (object,), {}) + B = type('B', (object,), {}) + C = type('C', (object,), {}) + a = A() + self.assertRaises(self.failureException, self.assertIsInstance, a, (B, C)) + + + def test_assertIsInstanceCustomMessage(self): + """ + If L{TestCase.assertIsInstance} is passed a custom message as its 3rd + argument, the message is included in the failure exception raised when + the assertion fails. + """ + exc = self.assertRaises( + self.failureException, + self.assertIsInstance, 3, str, "Silly assertion") + self.assertIn("Silly assertion", str(exc)) + + + def test_assertNotIsInstance(self): + """ + Test a true condition of assertNotIsInstance. + """ + A = type('A', (object,), {}) + B = type('B', (object,), {}) + a = A() + self.assertNotIsInstance(a, B) + + + def test_assertNotIsInstanceMultipleClasses(self): + """ + Test a true condition of assertNotIsInstance and multiple classes. + """ + A = type('A', (object,), {}) + B = type('B', (object,), {}) + C = type('C', (object,), {}) + a = A() + self.assertNotIsInstance(a, (B, C)) + + + def test_assertNotIsInstanceError(self): + """ + Test an error with assertNotIsInstance. + """ + A = type('A', (object,), {}) + a = A() + error = self.assertRaises(self.failureException, + self.assertNotIsInstance, a, A) + self.assertEqual(str(error), "%r is an instance of %s" % (a, A)) + + + def test_assertNotIsInstanceErrorMultipleClasses(self): + """ + Test an error with assertNotIsInstance and multiple classes. + """ + A = type('A', (object,), {}) + B = type('B', (object,), {}) + a = A() + self.assertRaises(self.failureException, self.assertNotIsInstance, a, (A, B)) + + + def test_assertDictEqual(self): + """ + L{twisted.trial.unittest.TestCase} supports the C{assertDictEqual} + method inherited from the standard library in Python 2.7. + """ + self.assertDictEqual({'a': 1}, {'a': 1}) + if getattr(unittest.SynchronousTestCase, 'assertDictEqual', None) is None: + test_assertDictEqual.skip = ( + "assertDictEqual is not available on this version of Python") + + + +class TestAsynchronousAssertions(unittest.TestCase): + """ + Tests for L{TestCase}'s asynchronous extensions to L{SynchronousTestCase}. + That is, assertFailure. + """ def test_assertFailure(self): d = defer.maybeDeferred(lambda: 1/0) return self.assertFailure(d, ZeroDivisionError) + def test_assertFailure_wrongException(self): d = defer.maybeDeferred(lambda: 1/0) self.assertFailure(d, OverflowError) @@ -307,6 +611,7 @@ lambda x: x.trap(self.failureException)) return d + def test_assertFailure_noException(self): d = defer.succeed(None) self.assertFailure(d, ZeroDivisionError) @@ -314,6 +619,7 @@ lambda x: x.trap(self.failureException)) return d + def test_assertFailure_moreInfo(self): """ In the case of assertFailure failing, check that we get lots of @@ -328,12 +634,14 @@ d.addErrback(self._checkInfo, f) return d + def _checkInfo(self, assertionFailure, f): assert assertionFailure.check(self.failureException) output = assertionFailure.getErrorMessage() self.assertIn(f.getErrorMessage(), output) self.assertIn(f.getBriefTraceback(), output) + def test_assertFailure_masked(self): """ A single wrong assertFailure should fail the whole test. @@ -355,6 +663,7 @@ self.assertEqual(1, len(result.failures)) +class WarningAssertionTests(unittest.SynchronousTestCase): def test_assertWarns(self): """ Test basic assertWarns report. @@ -549,108 +858,8 @@ self.assertEqual(warning['message'], "foo") - def test_assertIsInstance(self): - """ - Test a true condition of assertIsInstance. - """ - A = type('A', (object,), {}) - a = A() - self.assertIsInstance(a, A) - - def test_assertIsInstanceMultipleClasses(self): - """ - Test a true condition of assertIsInstance with multiple classes. - """ - A = type('A', (object,), {}) - B = type('B', (object,), {}) - a = A() - self.assertIsInstance(a, (A, B)) - - def test_assertIsInstanceError(self): - """ - Test an error with assertIsInstance. - """ - A = type('A', (object,), {}) - B = type('B', (object,), {}) - a = A() - self.assertRaises(self.failureException, self.assertIsInstance, a, B) - - def test_assertIsInstanceErrorMultipleClasses(self): - """ - Test an error with assertIsInstance and multiple classes. - """ - A = type('A', (object,), {}) - B = type('B', (object,), {}) - C = type('C', (object,), {}) - a = A() - self.assertRaises(self.failureException, self.assertIsInstance, a, (B, C)) - - - def test_assertIsInstanceCustomMessage(self): - """ - If L{TestCase.assertIsInstance} is passed a custom message as its 3rd - argument, the message is included in the failure exception raised when - the assertion fails. - """ - exc = self.assertRaises( - self.failureException, - self.assertIsInstance, 3, str, "Silly assertion") - self.assertIn("Silly assertion", str(exc)) - - - def test_assertNotIsInstance(self): - """ - Test a true condition of assertNotIsInstance. - """ - A = type('A', (object,), {}) - B = type('B', (object,), {}) - a = A() - self.assertNotIsInstance(a, B) - - def test_assertNotIsInstanceMultipleClasses(self): - """ - Test a true condition of assertNotIsInstance and multiple classes. - """ - A = type('A', (object,), {}) - B = type('B', (object,), {}) - C = type('C', (object,), {}) - a = A() - self.assertNotIsInstance(a, (B, C)) - - def test_assertNotIsInstanceError(self): - """ - Test an error with assertNotIsInstance. - """ - A = type('A', (object,), {}) - a = A() - error = self.assertRaises(self.failureException, - self.assertNotIsInstance, a, A) - self.assertEqual(str(error), "%r is an instance of %s" % (a, A)) - - - def test_assertNotIsInstanceErrorMultipleClasses(self): - """ - Test an error with assertNotIsInstance and multiple classes. - """ - A = type('A', (object,), {}) - B = type('B', (object,), {}) - a = A() - self.assertRaises(self.failureException, self.assertNotIsInstance, a, (A, B)) - - - def test_assertDictEqual(self): - """ - L{twisted.trial.unittest.TestCase} supports the C{assertDictEqual} - method inherited from the standard library in Python 2.7. - """ - self.assertDictEqual({'a': 1}, {'a': 1}) - if getattr(unittest.TestCase, 'assertDictEqual', None) is None: - test_assertDictEqual.skip = ( - "assertDictEqual is not available on this version of Python") - - -class TestAssertionNames(unittest.TestCase): +class TestAssertionNames(unittest.SynchronousTestCase): """ Tests for consistency of naming within TestCase assertion methods """ @@ -679,8 +888,8 @@ def test_failIf_matches_assertNot(self): - asserts = reflect.prefixedMethods(unittest.TestCase, 'assertNot') - failIfs = reflect.prefixedMethods(unittest.TestCase, 'failIf') + asserts = reflect.prefixedMethods(unittest.SynchronousTestCase, 'assertNot') + failIfs = reflect.prefixedMethods(unittest.SynchronousTestCase, 'failIf') self.assertEqual(sorted(asserts, key=self._name), sorted(failIfs, key=self._name)) @@ -698,9 +907,9 @@ self.assertEqual(value, getattr(self, name[:-1])) -class TestCallDeprecated(unittest.TestCase): +class TestCallDeprecated(unittest.SynchronousTestCase): """ - Test use of the L{TestCase.callDeprecated} method with version objects. + Test use of the L{SynchronousTestCase.callDeprecated} method with version objects. """ version = Version('Twisted', 8, 0, 0) diff -Nru twisted-12.0.0/twisted/trial/test/test_log.py twisted-12.2.0/twisted/trial/test/test_log.py --- twisted-12.0.0/twisted/trial/test/test_log.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_log.py 2012-08-17 13:50:10.000000000 +0000 @@ -4,6 +4,7 @@ """ Test the interaction between trial and errors logged during test run. """ +from __future__ import division import time @@ -23,12 +24,12 @@ return f + class Mask(object): """ Hide C{MockTest}s from Trial's automatic test finder. """ - - class MockTest(unittest.TestCase): + class FailureLoggingMixin(object): def test_silent(self): """ Don't log any errors. @@ -47,6 +48,12 @@ log.err(makeFailure()) log.err(makeFailure()) + + class SynchronousFailureLogging(FailureLoggingMixin, unittest.SynchronousTestCase): + pass + + + class AsynchronousFailureLogging(FailureLoggingMixin, unittest.TestCase): def test_inCallback(self): """ Log an error in an asynchronous callback. @@ -54,10 +61,11 @@ return task.deferLater(reactor, 0, lambda: log.err(makeFailure())) -class TestObserver(unittest.TestCase): + +class TestObserver(unittest.SynchronousTestCase): """ Tests for L{unittest._LogObserver}, a helper for the implementation of - L{TestCase.flushLoggedErrors}. + L{SynchronousTestCase.flushLoggedErrors}. """ def setUp(self): self.result = reporter.TestResult() @@ -144,7 +152,7 @@ -class LogErrors(unittest.TestCase): +class LogErrorsMixin(object): """ High-level tests demonstrating the expected behaviour of logged errors during tests. @@ -156,42 +164,72 @@ def tearDown(self): self.flushLoggedErrors(ZeroDivisionError) + def test_singleError(self): """ Test that a logged error gets reported as a test error. """ - test = Mask.MockTest('test_single') + test = self.MockTest('test_single') test(self.result) self.assertEqual(len(self.result.errors), 1) self.assertTrue(self.result.errors[0][1].check(ZeroDivisionError), self.result.errors[0][1]) + self.assertEqual(0, self.result.successes) + def test_twoErrors(self): """ Test that when two errors get logged, they both get reported as test errors. """ - test = Mask.MockTest('test_double') + test = self.MockTest('test_double') test(self.result) self.assertEqual(len(self.result.errors), 2) + self.assertEqual(0, self.result.successes) - def test_inCallback(self): - """ - Test that errors logged in callbacks get reported as test errors. - """ - test = Mask.MockTest('test_inCallback') - test(self.result) - self.assertEqual(len(self.result.errors), 1) - self.assertTrue(self.result.errors[0][1].check(ZeroDivisionError), - self.result.errors[0][1]) def test_errorsIsolated(self): """ Check that an error logged in one test doesn't fail the next test. """ - t1 = Mask.MockTest('test_single') - t2 = Mask.MockTest('test_silent') + t1 = self.MockTest('test_single') + t2 = self.MockTest('test_silent') t1(self.result) t2(self.result) self.assertEqual(len(self.result.errors), 1) self.assertEqual(self.result.errors[0][0], t1) + self.assertEqual(1, self.result.successes) + + + def test_boundedObservers(self): + """ + There are no extra log observers after a test runs. + """ + # XXX trial is *all about* global log state. It should really be fixed. + observer = unittest._LogObserver() + self.patch(unittest, '_logObserver', observer) + observers = log.theLogPublisher.observers[:] + test = self.MockTest() + test(self.result) + self.assertEqual(observers, log.theLogPublisher.observers) + + + +class SynchronousLogErrorsTests(LogErrorsMixin, unittest.SynchronousTestCase): + MockTest = Mask.SynchronousFailureLogging + + + +class AsynchronousLogErrorsTests(LogErrorsMixin, unittest.TestCase): + MockTest = Mask.AsynchronousFailureLogging + + def test_inCallback(self): + """ + Test that errors logged in callbacks get reported as test errors. + """ + test = self.MockTest('test_inCallback') + test(self.result) + self.assertEqual(len(self.result.errors), 1) + self.assertTrue(self.result.errors[0][1].check(ZeroDivisionError), + self.result.errors[0][1]) + diff -Nru twisted-12.0.0/twisted/trial/test/test_pyunitcompat.py twisted-12.2.0/twisted/trial/test/test_pyunitcompat.py --- twisted-12.0.0/twisted/trial/test/test_pyunitcompat.py 2011-02-14 04:45:15.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_pyunitcompat.py 2012-06-07 14:09:07.000000000 +0000 @@ -2,7 +2,7 @@ # See LICENSE for details. # # Maintainer: Jonathan Lange - +from __future__ import division import sys import traceback diff -Nru twisted-12.0.0/twisted/trial/test/test_reporter.py twisted-12.2.0/twisted/trial/test/test_reporter.py --- twisted-12.0.0/twisted/trial/test/test_reporter.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_reporter.py 2012-08-17 13:50:10.000000000 +0000 @@ -6,7 +6,7 @@ """ Tests for L{twisted.trial.reporter}. """ - +from __future__ import division import errno, sys, os, re, StringIO from inspect import getmro @@ -121,7 +121,8 @@ reported in the output stream with the I{ERROR} tag along with a summary of what error was reported and the ID of the test. """ - suite = self.loader.loadClass(erroneous.TestFailureInSetUp) + cls = erroneous.SynchronousTestFailureInSetUp + suite = self.loader.loadClass(cls) output = self.getOutput(suite).splitlines() match = [ self.doubleSeparator, @@ -132,7 +133,7 @@ r'.I am a broken setUp method.$'), ('twisted.trial.test.erroneous.FoolishError: ' 'I am a broken setUp method'), - 'twisted.trial.test.erroneous.TestFailureInSetUp.test_noop'] + '%s.%s.test_noop' % (cls.__module__, cls.__name__)] self.stringComparison(match, output) diff -Nru twisted-12.0.0/twisted/trial/test/test_script.py twisted-12.2.0/twisted/trial/test/test_script.py --- twisted-12.0.0/twisted/trial/test/test_script.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_script.py 2012-08-03 11:10:08.000000000 +0000 @@ -6,7 +6,7 @@ from twisted.trial import unittest, runner from twisted.scripts import trial -from twisted.python import util, deprecate, versions +from twisted.python import util from twisted.python.compat import set from twisted.python.filepath import FilePath @@ -16,7 +16,9 @@ def sibpath(filename): - """For finding files in twisted/trial/test""" + """ + For finding files in twisted/trial/test + """ return util.sibpath(__file__, filename) @@ -439,44 +441,3 @@ self.assertEqual( options.coverdir(), FilePath(path).child("coverage")) - -class ExtraTests(unittest.TestCase): - """ - Tests for the I{extra} option. - """ - - def setUp(self): - self.config = trial.Options() - - - def tearDown(self): - self.config = None - - - def assertDeprecationWarning(self, deprecatedCallable, warnings): - """ - Check for a deprecation warning - """ - self.assertEqual(len(warnings), 1) - self.assertEqual(warnings[0]['category'], DeprecationWarning) - self.assertEqual(warnings[0]['message'], - deprecate.getDeprecationWarningString( - deprecatedCallable, versions.Version('Twisted', 11, 0, 0))) - - - def test_extraDeprecation(self): - """ - Check that --extra will emit a deprecation warning - """ - self.config.opt_extra('some.sample.test') - self.assertDeprecationWarning(self.config.opt_extra, - self.flushWarnings([self.test_extraDeprecation])) - - def test_xDeprecation(self): - """ - Check that -x will emit a deprecation warning - """ - self.config.opt_x('some.sample.text') - self.assertDeprecationWarning(self.config.opt_extra, - self.flushWarnings([self.test_xDeprecation])) - diff -Nru twisted-12.0.0/twisted/trial/test/test_testcase.py twisted-12.2.0/twisted/trial/test/test_testcase.py --- twisted-12.0.0/twisted/trial/test/test_testcase.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_testcase.py 2012-08-17 13:50:10.000000000 +0000 @@ -2,24 +2,17 @@ # See LICENSE for details. """ -Direct unit tests for L{twisted.trial.unittest.TestCase}. +Direct unit tests for L{twisted.trial.unittest.SynchronousTestCase} and +L{twisted.trial.unittest.TestCase}. """ -from twisted.trial.unittest import TestCase +from twisted.trial.unittest import SynchronousTestCase, TestCase -class TestCaseTests(TestCase): +class TestCaseMixin(object): """ L{TestCase} tests. """ - class MyTestCase(TestCase): - """ - Some test methods which can be used to test behaviors of - L{TestCase}. - """ - def test_1(self): - pass - def setUp(self): """ Create a couple instances of C{MyTestCase}, each for the same test @@ -37,7 +30,7 @@ self.assertTrue(self.first == self.first) self.assertTrue(self.first != self.second) self.assertFalse(self.first == self.second) - + def test_hashability(self): """ @@ -49,3 +42,27 @@ container[self.first] = None container[self.second] = None self.assertEqual(len(container), 2) + + + +class SynchronousTestCaseTests(TestCaseMixin, SynchronousTestCase): + class MyTestCase(SynchronousTestCase): + """ + Some test methods which can be used to test behaviors of + L{SynchronousTestCase}. + """ + def test_1(self): + pass + + + +# Yes, subclass SynchronousTestCase again. There are no interesting behaviors +# of self being tested below, only of self.MyTestCase. +class AsynchronousTestCaseTests(TestCaseMixin, SynchronousTestCase): + class MyTestCase(TestCase): + """ + Some test methods which can be used to test behaviors of + L{TestCase}. + """ + def test_1(self): + pass diff -Nru twisted-12.0.0/twisted/trial/test/test_tests.py twisted-12.2.0/twisted/trial/test/test_tests.py --- twisted-12.0.0/twisted/trial/test/test_tests.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_tests.py 2012-08-17 13:50:10.000000000 +0000 @@ -3,6 +3,20 @@ """ Tests for the behaviour of unit tests. + +Many tests in this module follow a simple pattern. A mixin is defined which +includes test methods for a certain feature. The mixin is inherited from twice, +once by a class also inheriting from SynchronousTestCase and once from a class +inheriting from TestCase. These two subclasses are named like +I{SynchronousFooTests} and I{AsynchronousFooTests}, where I{Foo} is related to +the name of the mixin. + +This pattern allows the same tests to be applied to the two base test case +classes trial provides, ensuring their behavior is the same. + +Most new tests should be added in this pattern. Tests for functionality which +is intentionally only provided by TestCase, not SynchronousTestCase, is excepted +of course. """ import gc, StringIO, sys, weakref @@ -13,18 +27,27 @@ from twisted.trial.test.test_reporter import LoggingReporter -class ResultsTestMixin: +class ResultsTestMixin(object): + """ + Provide useful APIs for test cases that are about test cases. + """ def loadSuite(self, suite): + """ + Load tests from the given test case class and create a new reporter to + use for running it. + """ self.loader = runner.TestLoader() self.suite = self.loader.loadClass(suite) self.reporter = reporter.TestResult() + def test_setUp(self): self.failUnless(self.reporter.wasSuccessful()) self.assertEqual(self.reporter.errors, []) self.assertEqual(self.reporter.failures, []) self.assertEqual(self.reporter.skips, []) + def assertCount(self, numTests): self.assertEqual(self.suite.countTestCases(), numTests) self.suite(self.reporter) @@ -32,11 +55,10 @@ -class TestSuccess(unittest.TestCase): +class SuccessMixin(object): """ - Test that successful tests are reported as such. + Tests for the reporting of successful tests. """ - def setUp(self): self.result = reporter.TestResult() @@ -61,17 +83,17 @@ Test that when a successful test is run, it is reported as a success, and not as any other kind of result. """ - test = TestSuccess('test_successful') + test = self.__class__('test_successful') test.run(self.result) self.assertSuccessful(test, self.result) def test_defaultIsSuccessful(self): """ - Test that L{unittest.TestCase} itself can be instantiated, run, and + The test case type can be instantiated with no arguments, run, and reported as being successful. """ - test = unittest.TestCase() + test = self.__class__() test.run(self.result) self.assertSuccessful(test, self.result) @@ -80,7 +102,7 @@ """ Test that no reference is kept on a successful test. """ - test = TestSuccess('test_successful') + test = self.__class__('test_successful') ref = weakref.ref(test) test.run(self.result) self.assertSuccessful(test, self.result) @@ -90,49 +112,62 @@ -class TestSkipMethods(unittest.TestCase, ResultsTestMixin): - class SkippingTests(unittest.TestCase): - def test_skip1(self): - raise unittest.SkipTest('skip1') - - def test_skip2(self): - raise RuntimeError("I should not get raised") - test_skip2.skip = 'skip2' - - def test_skip3(self): - self.fail('I should not fail') - test_skip3.skip = 'skip3' +class SynchronousSuccessTests(SuccessMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ - class SkippingSetUp(unittest.TestCase): - def setUp(self): - raise unittest.SkipTest('skipSetUp') - def test_1(self): - pass - def test_2(self): - pass +class AsynchronousSuccessTests(SuccessMixin, unittest.TestCase): + """ + See module docstring. + """ + + +class SkipMethodsMixin(ResultsTestMixin): + """ + Tests for the reporting of skipping tests. + """ def setUp(self): - self.loadSuite(TestSkipMethods.SkippingTests) + self.loadSuite(self.Skipping) + def test_counting(self): self.assertCount(3) + def test_results(self): + """ + Running a suite in which all methods are individually set to skip + produces a successful result with no recorded errors or failures, all + the skipped methods recorded as skips, and no methods recorded as + successes. + """ self.suite(self.reporter) - self.failUnless(self.reporter.wasSuccessful()) + self.assertTrue(self.reporter.wasSuccessful()) self.assertEqual(self.reporter.errors, []) self.assertEqual(self.reporter.failures, []) self.assertEqual(len(self.reporter.skips), 3) + self.assertEqual(self.reporter.successes, 0) + def test_setUp(self): - self.loadSuite(TestSkipMethods.SkippingSetUp) + """ + Running a suite in which all methods are skipped by C{setUp} raising + L{SkipTest} produces a successful result with no recorded errors or + failures, all skipped methods recorded as skips, and no methods recorded + as successes. + """ + self.loadSuite(self.SkippingSetUp) self.suite(self.reporter) - self.failUnless(self.reporter.wasSuccessful()) + self.assertTrue(self.reporter.wasSuccessful()) self.assertEqual(self.reporter.errors, []) self.assertEqual(self.reporter.failures, []) self.assertEqual(len(self.reporter.skips), 2) + self.assertEqual(self.reporter.successes, 0) + def test_reasons(self): self.suite(self.reporter) @@ -143,25 +178,54 @@ str(reason)) -class TestSkipClasses(unittest.TestCase, ResultsTestMixin): - class SkippedClass(unittest.TestCase): - skip = 'class' - def setUp(self): - self.__class__._setUpRan = True - def test_skip1(self): - raise unittest.SkipTest('skip1') - def test_skip2(self): - raise RuntimeError("Ought to skip me") - test_skip2.skip = 'skip2' - def test_skip3(self): - pass - def test_skip4(self): - raise RuntimeError("Skip me too") + def test_deprecatedSkipWithoutReason(self): + """ + If a test method raises L{SkipTest} with no reason, a deprecation + warning is emitted. + """ + self.loadSuite(self.DeprecatedReasonlessSkip) + self.suite(self.reporter) + warnings = self.flushWarnings([ + self.DeprecatedReasonlessSkip.test_1]) + self.assertEqual(1, len(warnings)) + self.assertEqual(DeprecationWarning, warnings[0]['category']) + self.assertEqual( + "Do not raise unittest.SkipTest with no arguments! Give a reason " + "for skipping tests!", + warnings[0]['message']) + +class SynchronousSkipMethodTests(SkipMethodsMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + SynchronousSkipping as Skipping, + SynchronousSkippingSetUp as SkippingSetUp, + SynchronousDeprecatedReasonlessSkip as DeprecatedReasonlessSkip) + + + +class AsynchronousSkipMethodTests(SkipMethodsMixin, unittest.TestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + AsynchronousSkipping as Skipping, + AsynchronousSkippingSetUp as SkippingSetUp, + AsynchronousDeprecatedReasonlessSkip as DeprecatedReasonlessSkip) + + + + +class SkipClassesMixin(ResultsTestMixin): + """ + Test the class skipping features of L{twisted.trial.unittest.TestCase}. + """ def setUp(self): - self.loadSuite(TestSkipClasses.SkippedClass) - TestSkipClasses.SkippedClass._setUpRan = False + self.loadSuite(self.SkippedClass) + self.SkippedClass._setUpRan = False def test_counting(self): @@ -176,20 +240,22 @@ The C{setUp} method is not called if the class is set to skip. """ self.suite(self.reporter) - self.assertFalse(TestSkipClasses.SkippedClass._setUpRan) + self.assertFalse(self.SkippedClass._setUpRan) def test_results(self): """ Skipped test methods don't cause C{wasSuccessful} to return C{False}, - nor do they contribute to the C{errors} or C{failures} of the reporter. - They do, however, add elements to the reporter's C{skips} list. + nor do they contribute to the C{errors} or C{failures} of the reporter, + or to the count of successes. They do, however, add elements to the + reporter's C{skips} list. """ self.suite(self.reporter) - self.failUnless(self.reporter.wasSuccessful()) + self.assertTrue(self.reporter.wasSuccessful()) self.assertEqual(self.reporter.errors, []) self.assertEqual(self.reporter.failures, []) self.assertEqual(len(self.reporter.skips), 4) + self.assertEqual(self.reporter.successes, 0) def test_reasons(self): @@ -205,34 +271,55 @@ -class TestTodo(unittest.TestCase, ResultsTestMixin): - class TodoTests(unittest.TestCase): - def test_todo1(self): - self.fail("deliberate failure") - test_todo1.todo = "todo1" - - def test_todo2(self): - raise RuntimeError("deliberate error") - test_todo2.todo = "todo2" - - def test_todo3(self): - """unexpected success""" - test_todo3.todo = 'todo3' +class SynchronousSkipClassTests(SkipClassesMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + SynchronousSkippedClass as SkippedClass) + + +class AsynchronousSkipClassTests(SkipClassesMixin, unittest.TestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + AsynchronousSkippedClass as SkippedClass) + + + +class TodoMixin(ResultsTestMixin): + """ + Tests for the individual test method I{expected failure} features of + L{twisted.trial.unittest.TestCase}. + """ def setUp(self): - self.loadSuite(TestTodo.TodoTests) + self.loadSuite(self.Todo) + def test_counting(self): self.assertCount(3) + def test_results(self): + """ + Running a suite in which all methods are individually marked as expected + to fail produces a successful result with no recorded errors, failures, + or skips, all methods which fail and were expected to fail recorded as + C{expectedFailures}, and all methods which pass but which were expected + to fail recorded as C{unexpectedSuccesses}. Additionally, no tests are + recorded as successes. + """ self.suite(self.reporter) - self.failUnless(self.reporter.wasSuccessful()) + self.assertTrue(self.reporter.wasSuccessful()) self.assertEqual(self.reporter.errors, []) self.assertEqual(self.reporter.failures, []) self.assertEqual(self.reporter.skips, []) self.assertEqual(len(self.reporter.expectedFailures), 2) self.assertEqual(len(self.reporter.unexpectedSuccesses), 1) + self.assertEqual(self.reporter.successes, 0) + def test_expectedFailures(self): self.suite(self.reporter) @@ -241,6 +328,7 @@ for t, e, r in self.reporter.expectedFailures ] self.assertEqual(expectedReasons, reasonsGiven) + def test_unexpectedSuccesses(self): self.suite(self.reporter) expectedReasons = ['todo3'] @@ -249,34 +337,94 @@ self.assertEqual(expectedReasons, reasonsGiven) -class TestTodoClass(unittest.TestCase, ResultsTestMixin): - class TodoClass(unittest.TestCase): - def test_todo1(self): - pass - test_todo1.todo = "method" - def test_todo2(self): - pass - def test_todo3(self): - self.fail("Deliberate Failure") - test_todo3.todo = "method" - def test_todo4(self): - self.fail("Deliberate Failure") - TodoClass.todo = "class" + def test_expectedSetUpFailure(self): + """ + C{setUp} is excluded from the failure expectation defined by a C{todo} + attribute on a test method. + """ + self.loadSuite(self.SetUpTodo) + self.suite(self.reporter) + self.assertFalse(self.reporter.wasSuccessful()) + self.assertEqual(len(self.reporter.errors), 1) + self.assertEqual(self.reporter.failures, []) + self.assertEqual(self.reporter.skips, []) + self.assertEqual(len(self.reporter.expectedFailures), 0) + self.assertEqual(len(self.reporter.unexpectedSuccesses), 0) + self.assertEqual(self.reporter.successes, 0) + + + def test_expectedTearDownFailure(self): + """ + C{tearDown} is excluded from the failure expectation defined by a C{todo} + attribute on a test method. + """ + self.loadSuite(self.TearDownTodo) + self.suite(self.reporter) + self.assertFalse(self.reporter.wasSuccessful()) + self.assertEqual(len(self.reporter.errors), 1) + self.assertEqual(self.reporter.failures, []) + self.assertEqual(self.reporter.skips, []) + self.assertEqual(len(self.reporter.expectedFailures), 0) + # This seems strange, since tearDown raised an exception. However, the + # test method did complete without error. The tearDown error is + # reflected in the errors list, checked above. + self.assertEqual(len(self.reporter.unexpectedSuccesses), 1) + self.assertEqual(self.reporter.successes, 0) + + + +class SynchronousTodoTests(TodoMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + SynchronousTodo as Todo, + SynchronousSetUpTodo as SetUpTodo, + SynchronousTearDownTodo as TearDownTodo) + + +class AsynchronousTodoTests(TodoMixin, unittest.TestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + AsynchronousTodo as Todo, + AsynchronousSetUpTodo as SetUpTodo, + AsynchronousTearDownTodo as TearDownTodo) + + + +class ClassTodoMixin(ResultsTestMixin): + """ + Tests for the class-wide I{expected failure} features of + L{twisted.trial.unittest.TestCase}. + """ def setUp(self): - self.loadSuite(TestTodoClass.TodoClass) + self.loadSuite(self.TodoClass) def test_counting(self): self.assertCount(4) + def test_results(self): + """ + Running a suite in which an entire class is marked as expected to fail + produces a successful result with no recorded errors, failures, or + skips, all methods which fail and were expected to fail recorded as + C{expectedFailures}, and all methods which pass but which were expected + to fail recorded as C{unexpectedSuccesses}. Additionally, no tests are + recorded as successes. + """ self.suite(self.reporter) - self.failUnless(self.reporter.wasSuccessful()) + self.assertTrue(self.reporter.wasSuccessful()) self.assertEqual(self.reporter.errors, []) self.assertEqual(self.reporter.failures, []) self.assertEqual(self.reporter.skips, []) self.assertEqual(len(self.reporter.expectedFailures), 2) self.assertEqual(len(self.reporter.unexpectedSuccesses), 2) + self.assertEqual(self.reporter.successes, 0) + def test_expectedFailures(self): self.suite(self.reporter) @@ -293,51 +441,54 @@ self.assertEqual(expectedReasons, reasonsGiven) -class TestStrictTodo(unittest.TestCase, ResultsTestMixin): - class Todos(unittest.TestCase): - def test_todo1(self): - raise RuntimeError, "expected failure" - test_todo1.todo = (RuntimeError, "todo1") - - def test_todo2(self): - raise RuntimeError, "expected failure" - test_todo2.todo = ((RuntimeError, OSError), "todo2") - - def test_todo3(self): - raise RuntimeError, "we had no idea!" - test_todo3.todo = (OSError, "todo3") - - def test_todo4(self): - raise RuntimeError, "we had no idea!" - test_todo4.todo = ((OSError, SyntaxError), "todo4") - - def test_todo5(self): - self.fail("deliberate failure") - test_todo5.todo = (unittest.FailTest, "todo5") - - def test_todo6(self): - self.fail("deliberate failure") - test_todo6.todo = (RuntimeError, "todo6") - - def test_todo7(self): - pass - test_todo7.todo = (RuntimeError, "todo7") +class SynchronousClassTodoTests(ClassTodoMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + SynchronousTodoClass as TodoClass) + + + +class AsynchronousClassTodoTests(ClassTodoMixin, unittest.TestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + AsynchronousTodoClass as TodoClass) + + + +class StrictTodoMixin(ResultsTestMixin): + """ + Tests for the I{expected failure} features of + L{twisted.trial.unittest.TestCase} in which the exact failure which is + expected is indicated. + """ def setUp(self): - self.loadSuite(TestStrictTodo.Todos) + self.loadSuite(self.StrictTodo) def test_counting(self): self.assertCount(7) + def test_results(self): + """ + A test method which is marked as expected to fail with a particular + exception is only counted as an expected failure if it does fail with + that exception, not if it fails with some other exception. + """ self.suite(self.reporter) - self.failIf(self.reporter.wasSuccessful()) + self.assertFalse(self.reporter.wasSuccessful()) self.assertEqual(len(self.reporter.errors), 2) self.assertEqual(len(self.reporter.failures), 1) self.assertEqual(len(self.reporter.expectedFailures), 3) self.assertEqual(len(self.reporter.unexpectedSuccesses), 1) + self.assertEqual(self.reporter.successes, 0) self.assertEqual(self.reporter.skips, []) + def test_expectedFailures(self): self.suite(self.reporter) expectedReasons = ['todo1', 'todo2', 'todo5'] @@ -345,6 +496,7 @@ for t, e, r in self.reporter.expectedFailures ] self.assertEqual(expectedReasons, reasonsGotten) + def test_unexpectedSuccesses(self): self.suite(self.reporter) expectedReasons = [([RuntimeError], 'todo7')] @@ -354,7 +506,29 @@ -class TestCleanup(unittest.TestCase): +class SynchronousStrictTodoTests(StrictTodoMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + SynchronousStrictTodo as StrictTodo) + + + +class AsynchronousStrictTodoTests(StrictTodoMixin, unittest.TestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import ( + AsynchronousStrictTodo as StrictTodo) + + + +class TestReactorCleanup(unittest.TestCase): + """ + Tests for cleanup and reporting of reactor event sources left behind by test + methods. + """ def setUp(self): self.result = reporter.Reporter(StringIO.StringIO()) @@ -392,7 +566,7 @@ -class FixtureTest(unittest.TestCase): +class FixtureMixin(object): """ Tests for broken fixture helper methods (e.g. setUp, tearDown). """ @@ -402,30 +576,56 @@ self.loader = runner.TestLoader() - def testBrokenSetUp(self): + def test_brokenSetUp(self): """ When setUp fails, the error is recorded in the result object. """ - self.loader.loadClass(erroneous.TestFailureInSetUp).run(self.reporter) - self.assert_(len(self.reporter.errors) > 0) - self.assert_(isinstance(self.reporter.errors[0][1].value, - erroneous.FoolishError)) + suite = self.loader.loadClass(self.TestFailureInSetUp) + suite.run(self.reporter) + self.assertTrue(len(self.reporter.errors) > 0) + self.assertIsInstance( + self.reporter.errors[0][1].value, erroneous.FoolishError) + self.assertEqual(0, self.reporter.successes) - def testBrokenTearDown(self): + def test_brokenTearDown(self): """ When tearDown fails, the error is recorded in the result object. """ - suite = self.loader.loadClass(erroneous.TestFailureInTearDown) + suite = self.loader.loadClass(self.TestFailureInTearDown) suite.run(self.reporter) errors = self.reporter.errors - self.assert_(len(errors) > 0) - self.assert_(isinstance(errors[0][1].value, erroneous.FoolishError)) + self.assertTrue(len(errors) > 0) + self.assertIsInstance(errors[0][1].value, erroneous.FoolishError) + self.assertEqual(0, self.reporter.successes) + +class SynchronousFixtureTest(FixtureMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + from twisted.trial.test.erroneous import ( + SynchronousTestFailureInSetUp as TestFailureInSetUp, + SynchronousTestFailureInTearDown as TestFailureInTearDown) -class SuppressionTest(unittest.TestCase): + +class AsynchronousFixtureTest(FixtureMixin, unittest.TestCase): + """ + See module docstring. + """ + from twisted.trial.test.erroneous import ( + AsynchronousTestFailureInSetUp as TestFailureInSetUp, + AsynchronousTestFailureInTearDown as TestFailureInTearDown) + + + +class SuppressionMixin(object): + """ + Tests for the warning suppression features of + L{twisted.trial.unittest.SynchronousTestCase}. + """ def runTests(self, suite): suite.run(reporter.TestResult()) @@ -434,32 +634,82 @@ self.loader = runner.TestLoader() + def _assertWarnings(self, warnings, which): + """ + Assert that a certain number of warnings with certain messages were + emitted in a certain order. + + @param warnings: A list of emitted warnings, as returned by + C{flushWarnings}. + + @param which: A list of strings giving warning messages that should + appear in C{warnings}. + + @raise self.failureException: If the warning messages given by C{which} + do not match the messages in the warning information in C{warnings}, + or if they do not appear in the same order. + """ + self.assertEqual( + [warning['message'] for warning in warnings], + which) + + + def test_setUpSuppression(self): + """ + Suppressions defined by the test method being run are applied to any + warnings emitted while running the C{setUp} fixture. + """ + self.runTests( + self.loader.loadMethod( + self.TestSetUpSuppression.testSuppressMethod)) + warningsShown = self.flushWarnings([ + self.TestSetUpSuppression._emit]) + self._assertWarnings( + warningsShown, + [suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG, + suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG]) + + + def test_tearDownSuppression(self): + """ + Suppressions defined by the test method being run are applied to any + warnings emitted while running the C{tearDown} fixture. + """ + self.runTests( + self.loader.loadMethod( + self.TestTearDownSuppression.testSuppressMethod)) + warningsShown = self.flushWarnings([ + self.TestTearDownSuppression._emit]) + self._assertWarnings( + warningsShown, + [suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG, + suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG]) + + def test_suppressMethod(self): """ A suppression set on a test method prevents warnings emitted by that test method which the suppression matches from being emitted. """ self.runTests(self.loader.loadMethod( - suppression.TestSuppression.testSuppressMethod)) + self.TestSuppression.testSuppressMethod)) warningsShown = self.flushWarnings([ - suppression.TestSuppression._emit]) - self.assertEqual( - warningsShown[0]['message'], suppression.CLASS_WARNING_MSG) - self.assertEqual( - warningsShown[1]['message'], suppression.MODULE_WARNING_MSG) - self.assertEqual(len(warningsShown), 2) + self.TestSuppression._emit]) + self._assertWarnings( + warningsShown, + [suppression.CLASS_WARNING_MSG, suppression.MODULE_WARNING_MSG]) def test_suppressClass(self): """ - A suppression set on a L{TestCase} subclass prevents warnings emitted - by any test methods defined on that class which match the suppression - from being emitted. + A suppression set on a L{SynchronousTestCase} subclass prevents warnings + emitted by any test methods defined on that class which match the + suppression from being emitted. """ self.runTests(self.loader.loadMethod( - suppression.TestSuppression.testSuppressClass)) + self.TestSuppression.testSuppressClass)) warningsShown = self.flushWarnings([ - suppression.TestSuppression._emit]) + self.TestSuppression._emit]) self.assertEqual( warningsShown[0]['message'], suppression.METHOD_WARNING_MSG) self.assertEqual( @@ -474,9 +724,9 @@ emitted. """ self.runTests(self.loader.loadMethod( - suppression.TestSuppression2.testSuppressModule)) + self.TestSuppression2.testSuppressModule)) warningsShown = self.flushWarnings([ - suppression.TestSuppression._emit]) + self.TestSuppression._emit]) self.assertEqual( warningsShown[0]['message'], suppression.METHOD_WARNING_MSG) self.assertEqual( @@ -491,10 +741,10 @@ method, the warning is emitted, even if a wider suppression matches. """ case = self.loader.loadMethod( - suppression.TestSuppression.testOverrideSuppressClass) + self.TestSuppression.testOverrideSuppressClass) self.runTests(case) warningsShown = self.flushWarnings([ - suppression.TestSuppression._emit]) + self.TestSuppression._emit]) self.assertEqual( warningsShown[0]['message'], suppression.METHOD_WARNING_MSG) self.assertEqual( @@ -505,6 +755,30 @@ +class SynchronousSuppressionTest(SuppressionMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + from twisted.trial.test.suppression import ( + SynchronousTestSetUpSuppression as TestSetUpSuppression, + SynchronousTestTearDownSuppression as TestTearDownSuppression, + SynchronousTestSuppression as TestSuppression, + SynchronousTestSuppression2 as TestSuppression2) + + + +class AsynchronousSuppressionTest(SuppressionMixin, unittest.TestCase): + """ + See module docstring. + """ + from twisted.trial.test.suppression import ( + AsynchronousTestSetUpSuppression as TestSetUpSuppression, + AsynchronousTestTearDownSuppression as TestTearDownSuppression, + AsynchronousTestSuppression as TestSuppression, + AsynchronousTestSuppression2 as TestSuppression2) + + + class GCMixin: """ I provide a few mock tests that log setUp, tearDown, test execution and @@ -543,7 +817,7 @@ -class TestGarbageCollectionDefault(GCMixin, unittest.TestCase): +class TestGarbageCollectionDefault(GCMixin, unittest.SynchronousTestCase): def test_collectNotDefault(self): """ @@ -556,7 +830,7 @@ -class TestGarbageCollection(GCMixin, unittest.TestCase): +class TestGarbageCollection(GCMixin, unittest.SynchronousTestCase): def test_collectCalled(self): """ @@ -614,38 +888,14 @@ -class TestAddCleanup(unittest.TestCase): +class AddCleanupMixin(object): """ Test the addCleanup method of TestCase. """ - - class MockTest(unittest.TestCase): - - def setUp(self): - self.log = ['setUp'] - - def brokenSetUp(self): - self.log = ['setUp'] - raise RuntimeError("Deliberate failure") - - def skippingSetUp(self): - self.log = ['setUp'] - raise unittest.SkipTest("Don't do this") - - def append(self, thing): - self.log.append(thing) - - def tearDown(self): - self.log.append('tearDown') - - def runTest(self): - self.log.append('runTest') - - def setUp(self): - unittest.TestCase.setUp(self) + super(AddCleanupMixin, self).setUp() self.result = reporter.TestResult() - self.test = TestAddCleanup.MockTest() + self.test = self.AddCleanup() def test_addCleanupCalledIfSetUpFails(self): @@ -682,23 +932,6 @@ self.test.log) - def test_addCleanupWaitsForDeferreds(self): - """ - If an added callable returns a L{Deferred}, then the test should wait - until that L{Deferred} has fired before running the next cleanup - method. - """ - def cleanup(message): - d = defer.Deferred() - reactor.callLater(0, d.callback, message) - return d.addCallback(self.test.append) - self.test.addCleanup(self.test.append, 'foo') - self.test.addCleanup(cleanup, 'bar') - self.test.run(self.result) - self.assertEqual(['setUp', 'runTest', 'bar', 'foo', 'tearDown'], - self.test.log) - - def test_errorInCleanupIsCaptured(self): """ Errors raised in cleanup functions should be treated like errors in @@ -749,19 +982,49 @@ -class TestSuiteClearing(unittest.TestCase): +class SynchronousAddCleanupTests(AddCleanupMixin, unittest.SynchronousTestCase): """ - Tests for our extension that allows us to clear out a L{TestSuite}. + See module docstring. """ + from twisted.trial.test.skipping import SynchronousAddCleanup as AddCleanup + +class AsynchronousAddCleanupTests(AddCleanupMixin, unittest.TestCase): + """ + See module docstring. + """ + from twisted.trial.test.skipping import AsynchronousAddCleanup as AddCleanup + + def test_addCleanupWaitsForDeferreds(self): + """ + If an added callable returns a L{Deferred}, then the test should wait + until that L{Deferred} has fired before running the next cleanup + method. + """ + def cleanup(message): + d = defer.Deferred() + reactor.callLater(0, d.callback, message) + return d.addCallback(self.test.append) + self.test.addCleanup(self.test.append, 'foo') + self.test.addCleanup(cleanup, 'bar') + self.test.run(self.result) + self.assertEqual(['setUp', 'runTest', 'bar', 'foo', 'tearDown'], + self.test.log) + + + +class SuiteClearingMixin(object): + """ + Tests for our extension that allows us to clear out a L{TestSuite}. + """ def test_clearSuite(self): """ Calling L{unittest._clearSuite} on a populated L{TestSuite} removes all tests. """ suite = unittest.TestSuite() - suite.addTest(unittest.TestCase()) + suite.addTest(self.TestCase()) # Double check that the test suite actually has something in it. self.assertEqual(1, suite.countTestCases()) unittest._clearSuite(suite) @@ -778,7 +1041,7 @@ """ pyunit = __import__('unittest') suite = pyunit.TestSuite() - suite.addTest(unittest.TestCase()) + suite.addTest(self.TestCase()) # Double check that the test suite actually has something in it. self.assertEqual(1, suite.countTestCases()) unittest._clearSuite(suite) @@ -786,12 +1049,26 @@ -class TestTestDecorator(unittest.TestCase): +class SynchronousSuiteClearingTests(SuiteClearingMixin, unittest.SynchronousTestCase): """ - Tests for our test decoration features. + See module docstring. """ + TestCase = unittest.SynchronousTestCase + +class AsynchronousSuiteClearingTests(SuiteClearingMixin, unittest.TestCase): + """ + See module docstring. + """ + TestCase = unittest.TestCase + + + +class TestDecoratorMixin(object): + """ + Tests for our test decoration features. + """ def assertTestsEqual(self, observed, expected): """ Assert that the given decorated tests are equal. @@ -828,7 +1105,7 @@ See L{reporter._AdaptedReporter}. """ - test = unittest.TestCase() + test = self.TestCase() decoratedTest = unittest.TestDecorator(test) result = LoggingReporter() decoratedTest.run(result) @@ -843,7 +1120,7 @@ See L{reporter._AdaptedReporter}. """ - test = unittest.TestCase() + test = self.TestCase() decoratedTest = unittest.TestDecorator(test) result = LoggingReporter() decoratedTest(result) @@ -855,7 +1132,7 @@ Calling L{decorate} on a single test case returns the test case decorated with the provided decorator. """ - test = unittest.TestCase() + test = self.TestCase() decoratedTest = unittest.decorate(test, unittest.TestDecorator) self.assertTestsEqual(unittest.TestDecorator(test), decoratedTest) @@ -865,7 +1142,7 @@ Calling L{decorate} on a test suite will return a test suite with each test decorated with the provided decorator. """ - test = unittest.TestCase() + test = self.TestCase() suite = unittest.TestSuite([test]) decoratedTest = unittest.decorate(suite, unittest.TestDecorator) self.assertSuitesEqual( @@ -876,7 +1153,7 @@ """ Calling L{decorate} on a test suite will mutate the original suite. """ - test = unittest.TestCase() + test = self.TestCase() suite = unittest.TestSuite([test]) decoratedTest = unittest.decorate( suite, unittest.TestDecorator) @@ -899,7 +1176,7 @@ if getrefcount is None: raise unittest.SkipTest( "getrefcount not supported on this platform") - test = unittest.TestCase() + test = self.TestCase() suite = unittest.TestSuite([test]) count1 = getrefcount(test) decoratedTest = unittest.decorate(suite, unittest.TestDecorator) @@ -913,7 +1190,7 @@ test suite that maintains the same structure, but with all tests decorated. """ - test = unittest.TestCase() + test = self.TestCase() suite = unittest.TestSuite([unittest.TestSuite([test])]) decoratedTest = unittest.decorate(suite, unittest.TestDecorator) expected = unittest.TestSuite( @@ -926,7 +1203,7 @@ Calling L{decorate} on a test suite with already-decorated tests decorates all of the tests in the suite again. """ - test = unittest.TestCase() + test = self.TestCase() decoratedTest = unittest.decorate(test, unittest.TestDecorator) redecoratedTest = unittest.decorate(decoratedTest, unittest.TestDecorator) @@ -939,7 +1216,7 @@ Tests can be in non-standard suites. L{decorate} preserves the non-standard suites when it decorates the tests. """ - test = unittest.TestCase() + test = self.TestCase() suite = runner.DestructiveTestSuite([test]) decorated = unittest.decorate(suite, unittest.TestDecorator) self.assertSuitesEqual( @@ -947,17 +1224,32 @@ runner.DestructiveTestSuite([unittest.TestDecorator(test)])) -class TestMonkeyPatchSupport(unittest.TestCase): + +class SynchronousTestDecoratorTests(TestDecoratorMixin, unittest.SynchronousTestCase): """ - Tests for the patch() helper method in L{unittest.TestCase}. + See module docstring. """ + TestCase = unittest.SynchronousTestCase + + + +class AsynchronousTestDecoratorTests(TestDecoratorMixin, unittest.TestCase): + """ + See module docstring. + """ + TestCase = unittest.TestCase + +class MonkeyPatchMixin(object): + """ + Tests for the patch() helper method in L{unittest.TestCase}. + """ def setUp(self): self.originalValue = 'original' self.patchedValue = 'patched' self.objectToPatch = self.originalValue - self.test = unittest.TestCase() + self.test = self.TestCase() def test_patch(self): @@ -1013,18 +1305,33 @@ -class TestIterateTests(unittest.TestCase): +class SynchronousMonkeyPatchTests(MonkeyPatchMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + TestCase = unittest.SynchronousTestCase + + + +class AsynchronousMonkeyPatchTests(MonkeyPatchMixin, unittest.TestCase): + """ + See module docstring. + """ + TestCase = unittest.TestCase + + + +class IterateTestsMixin(object): """ L{_iterateTests} returns a list of all test cases in a test suite or test case. """ - def test_iterateTestCase(self): """ L{_iterateTests} on a single test case returns a list containing that test case. """ - test = unittest.TestCase() + test = self.TestCase() self.assertEqual([test], list(unittest._iterateTests(test))) @@ -1033,7 +1340,7 @@ L{_iterateTests} on a test suite that contains a single test case returns a list containing that test case. """ - test = unittest.TestCase() + test = self.TestCase() suite = runner.TestSuite([test]) self.assertEqual([test], list(unittest._iterateTests(suite))) @@ -1042,7 +1349,7 @@ """ L{_iterateTests} returns tests that are in nested test suites. """ - test = unittest.TestCase() + test = self.TestCase() suite = runner.TestSuite([runner.TestSuite([test])]) self.assertEqual([test], list(unittest._iterateTests(suite))) @@ -1051,6 +1358,22 @@ """ L{_iterateTests} returns tests in left-to-right, depth-first order. """ - test = unittest.TestCase() + test = self.TestCase() suite = runner.TestSuite([runner.TestSuite([test]), self]) self.assertEqual([test, self], list(unittest._iterateTests(suite))) + + + +class SynchronousIterateTestsTests(IterateTestsMixin, unittest.SynchronousTestCase): + """ + See module docstring. + """ + TestCase = unittest.SynchronousTestCase + + + +class AsynchronousIterateTestsTests(IterateTestsMixin, unittest.TestCase): + """ + See module docstring. + """ + TestCase = unittest.TestCase diff -Nru twisted-12.0.0/twisted/trial/test/test_util.py twisted-12.2.0/twisted/trial/test/test_util.py --- twisted-12.0.0/twisted/trial/test/test_util.py 2011-07-14 19:05:14.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_util.py 2012-08-17 13:50:10.000000000 +0000 @@ -14,45 +14,70 @@ from twisted.internet import defer from twisted.internet.base import DelayedCall -from twisted.trial.unittest import TestCase +from twisted.trial.unittest import SynchronousTestCase, TestCase from twisted.trial import util from twisted.trial.util import DirtyReactorAggregateError, _Janitor -from twisted.trial.test import packages +from twisted.trial.test import packages, suppression -class TestMktemp(TestCase): +class TestMktemp(SynchronousTestCase): + """ + Tests for L{TestCase.mktemp}, a helper function for creating temporary file + or directory names. + """ def test_name(self): + """ + The path name returned by C{mktemp} is directly beneath a directory + which identifies the test method which created the name. + """ name = self.mktemp() dirs = os.path.dirname(name).split(os.sep)[:-1] self.assertEqual( dirs, ['twisted.trial.test.test_util', 'TestMktemp', 'test_name']) + def test_unique(self): + """ + Repeated calls to C{mktemp} return different values. + """ name = self.mktemp() - self.failIfEqual(name, self.mktemp()) + self.assertNotEqual(name, self.mktemp()) + def test_created(self): + """ + The directory part of the path name returned by C{mktemp} exists. + """ name = self.mktemp() dirname = os.path.dirname(name) - self.failUnless(os.path.exists(dirname)) - self.failIf(os.path.exists(name)) + self.assertTrue(os.path.exists(dirname)) + self.assertFalse(os.path.exists(name)) + def test_location(self): + """ + The path returned by C{mktemp} is beneath the current working directory. + """ path = os.path.abspath(self.mktemp()) - self.failUnless(path.startswith(os.getcwd())) + self.assertTrue(path.startswith(os.getcwd())) -class TestIntrospection(TestCase): + +class TestIntrospection(SynchronousTestCase): def test_containers(self): - import suppression + """ + When pased a test case, L{util.getPythonContainers} returns a list + including the test case and the module the test case is defined in. + """ parents = util.getPythonContainers( - suppression.TestSuppression2.testSuppressModule) - expected = [suppression.TestSuppression2, suppression] + suppression.SynchronousTestSuppression2.testSuppressModule) + expected = [suppression.SynchronousTestSuppression2, suppression] for a, b in zip(parents, expected): self.assertEqual(a, b) + class TestFindObject(packages.SysPathManglingTest): """ Tests for L{twisted.trial.util.findObject} @@ -254,7 +279,7 @@ -class DirtyReactorAggregateErrorTest(TestCase): +class DirtyReactorAggregateErrorTest(SynchronousTestCase): """ Tests for the L{DirtyReactorAggregateError}. """ @@ -371,7 +396,7 @@ -class JanitorTests(TestCase): +class JanitorTests(SynchronousTestCase): """ Tests for L{_Janitor}! """ diff -Nru twisted-12.0.0/twisted/trial/test/test_warning.py twisted-12.2.0/twisted/trial/test/test_warning.py --- twisted-12.0.0/twisted/trial/test/test_warning.py 2011-06-12 14:28:24.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/test_warning.py 2012-08-17 13:50:10.000000000 +0000 @@ -9,15 +9,15 @@ from StringIO import StringIO from twisted.python.filepath import FilePath -from twisted.trial.unittest import (TestCase, _collectWarnings, - _setWarningRegistryToNone) +from twisted.trial.unittest import ( + SynchronousTestCase, _collectWarnings, _setWarningRegistryToNone) from twisted.trial.reporter import TestResult class Mask(object): """ - Hide a L{TestCase} definition from trial's automatic discovery mechanism. + Hide a test case definition from trial's automatic discovery mechanism. """ - class MockTests(TestCase): + class MockTests(SynchronousTestCase): """ A test case which is used by L{FlushWarningsTests} to verify behavior which cannot be verified by code inside a single test method. @@ -41,9 +41,9 @@ -class FlushWarningsTests(TestCase): +class FlushWarningsTests(SynchronousTestCase): """ - Tests for L{TestCase.flushWarnings}, an API for examining the warnings + Tests for C{flushWarnings}, an API for examining the warnings emitted so far in a test. """ @@ -69,16 +69,16 @@ def test_none(self): """ - If no warnings are emitted by a test, L{TestCase.flushWarnings} returns - an empty list. + If no warnings are emitted by a test, C{flushWarnings} returns an empty + list. """ self.assertEqual(self.flushWarnings(), []) def test_several(self): """ - If several warnings are emitted by a test, L{TestCase.flushWarnings} - returns a list containing all of them. + If several warnings are emitted by a test, C{flushWarnings} returns a + list containing all of them. """ firstMessage = "first warning message" firstCategory = UserWarning @@ -97,7 +97,7 @@ def test_repeated(self): """ The same warning triggered twice from the same place is included twice - in the list returned by L{TestCase.flushWarnings}. + in the list returned by C{flushWarnings}. """ message = "the message" category = RuntimeWarning @@ -111,8 +111,8 @@ def test_cleared(self): """ - After a particular warning event has been returned by - L{TestCase.flushWarnings}, it is not returned by subsequent calls. + After a particular warning event has been returned by C{flushWarnings}, + it is not returned by subsequent calls. """ message = "the message" category = RuntimeWarning @@ -209,8 +209,8 @@ def test_multipleFlushes(self): """ - Any warnings emitted after a call to L{TestCase.flushWarnings} can be - flushed by another call to L{TestCase.flushWarnings}. + Any warnings emitted after a call to C{flushWarnings} can be flushed by + another call to C{flushWarnings}. """ warnings.warn("first message") self.assertEqual(len(self.flushWarnings()), 1) @@ -220,7 +220,7 @@ def test_filterOnOffendingFunction(self): """ - The list returned by L{TestCase.flushWarnings} includes only those + The list returned by C{flushWarnings} includes only those warnings which refer to the source of the function passed as the value for C{offendingFunction}, if a value is passed for that parameter. """ @@ -262,9 +262,9 @@ def test_invalidFilter(self): """ - If an object which is neither a function nor a method is included in - the C{offendingFunctions} list, L{TestCase.flushWarnings} raises - L{ValueError}. Such a call flushes no warnings. + If an object which is neither a function nor a method is included in the + C{offendingFunctions} list, C{flushWarnings} raises L{ValueError}. Such + a call flushes no warnings. """ warnings.warn("oh no") self.assertRaises(ValueError, self.flushWarnings, [None]) @@ -346,7 +346,7 @@ -class CollectWarningsTests(TestCase): +class CollectWarningsTests(SynchronousTestCase): """ Tests for L{_collectWarnings}. """ diff -Nru twisted-12.0.0/twisted/trial/test/weird.py twisted-12.2.0/twisted/trial/test/weird.py --- twisted-12.0.0/twisted/trial/test/weird.py 2006-09-19 06:43:01.000000000 +0000 +++ twisted-12.2.0/twisted/trial/test/weird.py 2012-06-07 14:09:07.000000000 +0000 @@ -1,3 +1,5 @@ +from __future__ import division + from twisted.trial import unittest from twisted.internet import defer diff -Nru twisted-12.0.0/twisted/trial/unittest.py twisted-12.2.0/twisted/trial/unittest.py --- twisted-12.0.0/twisted/trial/unittest.py 2011-10-17 19:26:52.000000000 +0000 +++ twisted-12.2.0/twisted/trial/unittest.py 2012-08-17 13:50:10.000000000 +0000 @@ -1,4 +1,4 @@ -# -*- test-case-name: twisted.trial.test.test_tests -*- +# -*- test-case-name: twisted.trial.test -*- # Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -16,7 +16,8 @@ from twisted.internet import defer, utils from twisted.python import components, failure, log, monkey -from twisted.python.deprecate import getDeprecationWarningString +from twisted.python.deprecate import ( + getDeprecationWarningString, warnAboutFunction) from twisted.trial import itrial, reporter, util @@ -537,19 +538,13 @@ def _add(self): if self._added == 0: log.addObserver(self.gotEvent) - self._oldFE, log._flushErrors = (log._flushErrors, self.flushErrors) - self._oldIE, log._ignore = (log._ignore, self._ignoreErrors) - self._oldCI, log._clearIgnores = (log._clearIgnores, - self._clearIgnores) self._added += 1 + def _remove(self): self._added -= 1 if self._added == 0: log.removeObserver(self.gotEvent) - log._flushErrors = self._oldFE - log._ignore = self._oldIE - log._clearIgnores = self._oldCI def _ignoreErrors(self, *errorTypes): @@ -612,22 +607,23 @@ _wait_is_running = [] -class TestCase(_Assertions): + +class SynchronousTestCase(_Assertions): """ A unit test. The atom of the unit testing universe. - This class extends C{unittest.TestCase} from the standard library. The - main feature is the ability to return C{Deferred}s from tests and fixture - methods and to have the suite wait for those C{Deferred}s to fire. - - To write a unit test, subclass C{TestCase} and define a method (say, - 'test_foo') on the subclass. To run the test, instantiate your subclass - with the name of the method, and call L{run} on the instance, passing a - L{TestResult} object. - - The C{trial} script will automatically find any C{TestCase} subclasses - defined in modules beginning with 'test_' and construct test cases for all - methods beginning with 'test'. + This class extends C{unittest.TestCase} from the standard library. A number + of convenient testing helpers are added, including logging and warning + integration, monkey-patching support, and more. + + To write a unit test, subclass C{SynchronousTestCase} and define a method + (say, 'test_foo') on the subclass. To run the test, instantiate your + subclass with the name of the method, and call L{run} on the instance, + passing a L{TestResult} object. + + The C{trial} script will automatically find any C{SynchronousTestCase} + subclasses defined in modules beginning with 'test_' and construct test + cases for all methods beginning with 'test'. If an error is logged during the test run, the test will fail with an error. See L{log.err}. @@ -642,40 +638,27 @@ reported to the result object as 'skipped' (if the C{TestResult} supports skipping). - @ivar suppress: C{None} or a list of tuples of C{(args, kwargs)} to be - passed to C{warnings.filterwarnings}. Use these to suppress warnings - raised in a test. Useful for testing deprecated code. See also - L{util.suppress}. - - @ivar timeout: A real number of seconds. If set, the test will - raise an error if it takes longer than C{timeout} seconds. - If not set, util.DEFAULT_TIMEOUT_DURATION is used. - @ivar todo: C{None}, a string or a tuple of C{(errors, reason)} where C{errors} is either an exception class or an iterable of exception classes, and C{reason} is a string. See L{Todo} or L{makeTodo} for more information. - """ - implements(itrial.ITestCase) + @ivar suppress: C{None} or a list of tuples of C{(args, kwargs)} to be + passed to C{warnings.filterwarnings}. Use these to suppress warnings + raised in a test. Useful for testing deprecated code. See also + L{util.suppress}. + """ failureException = FailTest def __init__(self, methodName='runTest'): - """ - Construct an asynchronous test case for C{methodName}. - - @param methodName: The name of a method on C{self}. This method should - be a unit test. That is, it should be a short method that calls some of - the assert* methods. If C{methodName} is unspecified, L{runTest} will - be used as the test method. This is mostly useful for testing Trial. - """ - super(TestCase, self).__init__(methodName) + super(SynchronousTestCase, self).__init__(methodName) + self._passed = False + self._cleanups = [] self._testMethodName = methodName testMethod = getattr(self, methodName) self._parents = [testMethod, self] self._parents.extend(util.getPythonContainers(testMethod)) - self._passed = False - self._cleanups = [] + if sys.version_info >= (2, 6): # Override the comparison defined by the base TestCase which considers @@ -695,218 +678,154 @@ return self is not other - def _run(self, methodName, result): - from twisted.internet import reactor - timeout = self.getTimeout() - def onTimeout(d): - e = defer.TimeoutError("%r (%s) still running at %s secs" - % (self, methodName, timeout)) - f = failure.Failure(e) - # try to errback the deferred that the test returns (for no gorram - # reason) (see issue1005 and test_errorPropagation in - # test_deferred) - try: - d.errback(f) - except defer.AlreadyCalledError: - # if the deferred has been called already but the *back chain - # is still unfinished, crash the reactor and report timeout - # error ourself. - reactor.crash() - self._timedOut = True # see self._wait - todo = self.getTodo() - if todo is not None and todo.expected(f): - result.addExpectedFailure(self, f, todo) - else: - result.addError(self, f) - onTimeout = utils.suppressWarnings( - onTimeout, util.suppress(category=DeprecationWarning)) - method = getattr(self, methodName) - d = defer.maybeDeferred(utils.runWithWarningsSuppressed, - self.getSuppress(), method) - call = reactor.callLater(timeout, onTimeout, d) - d.addBoth(lambda x : call.active() and call.cancel() or x) - return d - def shortDescription(self): - desc = super(TestCase, self).shortDescription() + desc = super(SynchronousTestCase, self).shortDescription() if desc is None: return self._testMethodName return desc - def __call__(self, *args, **kwargs): - return self.run(*args, **kwargs) - - def deferSetUp(self, ignored, result): - d = self._run('setUp', result) - d.addCallbacks(self.deferTestMethod, self._ebDeferSetUp, - callbackArgs=(result,), - errbackArgs=(result,)) - return d - - def _ebDeferSetUp(self, failure, result): - if failure.check(SkipTest): - result.addSkip(self, self._getReason(failure)) - else: - result.addError(self, failure) - if failure.check(KeyboardInterrupt): - result.stop() - return self.deferRunCleanups(None, result) - - def deferTestMethod(self, ignored, result): - d = self._run(self._testMethodName, result) - d.addCallbacks(self._cbDeferTestMethod, self._ebDeferTestMethod, - callbackArgs=(result,), - errbackArgs=(result,)) - d.addBoth(self.deferRunCleanups, result) - d.addBoth(self.deferTearDown, result) - return d - - def _cbDeferTestMethod(self, ignored, result): - if self.getTodo() is not None: - result.addUnexpectedSuccess(self, self.getTodo()) - else: - self._passed = True - return ignored - - def _ebDeferTestMethod(self, f, result): - todo = self.getTodo() - if todo is not None and todo.expected(f): - result.addExpectedFailure(self, f, todo) - elif f.check(self.failureException, FailTest): - result.addFailure(self, f) - elif f.check(KeyboardInterrupt): - result.addError(self, f) - result.stop() - elif f.check(SkipTest): - result.addSkip(self, self._getReason(f)) - else: - result.addError(self, f) - - def deferTearDown(self, ignored, result): - d = self._run('tearDown', result) - d.addErrback(self._ebDeferTearDown, result) - return d - - def _ebDeferTearDown(self, failure, result): - result.addError(self, failure) - if failure.check(KeyboardInterrupt): - result.stop() - self._passed = False - def deferRunCleanups(self, ignored, result): + def getSkip(self): """ - Run any scheduled cleanups and report errors (if any to the result - object. + Return the skip reason set on this test, if any is set. Checks on the + instance first, then the class, then the module, then packages. As + soon as it finds something with a C{skip} attribute, returns that. + Returns C{None} if it cannot find anything. See L{TestCase} docstring + for more details. """ - d = self._runCleanups() - d.addCallback(self._cbDeferRunCleanups, result) - return d + return util.acquireAttribute(self._parents, 'skip', None) - def _cbDeferRunCleanups(self, cleanupResults, result): - for flag, failure in cleanupResults: - if flag == defer.FAILURE: - result.addError(self, failure) - if failure.check(KeyboardInterrupt): - result.stop() - self._passed = False - def _cleanUp(self, result): - try: - clean = util._Janitor(self, result).postCaseCleanup() - if not clean: - self._passed = False - except: - result.addError(self, failure.Failure()) - self._passed = False - for error in self._observer.getErrors(): - result.addError(self, error) - self._passed = False - self.flushLoggedErrors() - self._removeObserver() - if self._passed: - result.addSuccess(self) + def getTodo(self): + """ + Return a L{Todo} object if the test is marked todo. Checks on the + instance first, then the class, then the module, then packages. As + soon as it finds something with a C{todo} attribute, returns that. + Returns C{None} if it cannot find anything. See L{TestCase} docstring + for more details. + """ + todo = util.acquireAttribute(self._parents, 'todo', None) + if todo is None: + return None + return makeTodo(todo) - def _classCleanUp(self, result): - try: - util._Janitor(self, result).postClassCleanup() - except: - result.addError(self, failure.Failure()) - def _makeReactorMethod(self, name): + def runTest(self): """ - Create a method which wraps the reactor method C{name}. The new - method issues a deprecation warning and calls the original. + If no C{methodName} argument is passed to the constructor, L{run} will + treat this method as the thing with the actual test inside. """ - def _(*a, **kw): - warnings.warn("reactor.%s cannot be used inside unit tests. " - "In the future, using %s will fail the test and may " - "crash or hang the test run." - % (name, name), - stacklevel=2, category=DeprecationWarning) - return self._reactorMethods[name](*a, **kw) - return _ - def _deprecateReactor(self, reactor): - """ - Deprecate C{iterate}, C{crash} and C{stop} on C{reactor}. That is, - each method is wrapped in a function that issues a deprecation - warning, then calls the original. - @param reactor: The Twisted reactor. + def run(self, result): """ - self._reactorMethods = {} - for name in ['crash', 'iterate', 'stop']: - self._reactorMethods[name] = getattr(reactor, name) - setattr(reactor, name, self._makeReactorMethod(name)) + Run the test case, storing the results in C{result}. - def _undeprecateReactor(self, reactor): - """ - Restore the deprecated reactor methods. Undoes what - L{_deprecateReactor} did. + First runs C{setUp} on self, then runs the test method (defined in the + constructor), then runs C{tearDown}. As with the standard library + L{unittest.TestCase}, the return value of these methods is disregarded. + In particular, returning a L{Deferred} has no special additional + consequences. - @param reactor: The Twisted reactor. + @param result: A L{TestResult} object. """ - for name, method in self._reactorMethods.iteritems(): - setattr(reactor, name, method) - self._reactorMethods = {} + log.msg("--> %s <--" % (self.id())) + new_result = itrial.IReporter(result, None) + if new_result is None: + result = PyUnitResultAdapter(result) + else: + result = new_result + result.startTest(self) + if self.getSkip(): # don't run test methods that are marked as .skip + result.addSkip(self, self.getSkip()) + result.stopTest(self) + return - def _installObserver(self): - self._observer = _logObserver - self._observer._add() + self._passed = False + self._warnings = [] - def _removeObserver(self): - self._observer._remove() + self._installObserver() + # All the code inside _runFixturesAndTest will be run such that warnings + # emitted by it will be collected and retrievable by flushWarnings. + _collectWarnings(self._warnings.append, self._runFixturesAndTest, result) - def flushLoggedErrors(self, *errorTypes): - """ - Remove stored errors received from the log. + # Any collected warnings which the test method didn't flush get + # re-emitted so they'll be logged or show up on stdout or whatever. + for w in self.flushWarnings(): + try: + warnings.warn_explicit(**w) + except: + result.addError(self, failure.Failure()) - C{TestCase} stores each error logged during the run of the test and - reports them as errors during the cleanup phase (after C{tearDown}). + result.stopTest(self) - @param *errorTypes: If unspecifed, flush all errors. Otherwise, only - flush errors that match the given types. - @return: A list of failures that have been removed. + def addCleanup(self, f, *args, **kwargs): """ - return self._observer.flushErrors(*errorTypes) + Add the given function to a list of functions to be called after the + test has run, but before C{tearDown}. + Functions will be run in reverse order of being added. This helps + ensure that tear down complements set up. - def flushWarnings(self, offendingFunctions=None): + As with all aspects of L{SynchronousTestCase}, Deferreds are not + supported in cleanup functions. """ - Remove stored warnings from the list of captured warnings and return - them. + self._cleanups.append((f, args, kwargs)) - @param offendingFunctions: If C{None}, all warnings issued during the - currently running test will be flushed. Otherwise, only warnings - which I{point} to a function included in this list will be flushed. - All warnings include a filename and source line number; if these + + def patch(self, obj, attribute, value): + """ + Monkey patch an object for the duration of the test. + + The monkey patch will be reverted at the end of the test using the + L{addCleanup} mechanism. + + The L{MonkeyPatcher} is returned so that users can restore and + re-apply the monkey patch within their tests. + + @param obj: The object to monkey patch. + @param attribute: The name of the attribute to change. + @param value: The value to set the attribute to. + @return: A L{monkey.MonkeyPatcher} object. + """ + monkeyPatch = monkey.MonkeyPatcher((obj, attribute, value)) + monkeyPatch.patch() + self.addCleanup(monkeyPatch.restore) + return monkeyPatch + + + def flushLoggedErrors(self, *errorTypes): + """ + Remove stored errors received from the log. + + C{TestCase} stores each error logged during the run of the test and + reports them as errors during the cleanup phase (after C{tearDown}). + + @param *errorTypes: If unspecifed, flush all errors. Otherwise, only + flush errors that match the given types. + + @return: A list of failures that have been removed. + """ + return self._observer.flushErrors(*errorTypes) + + + def flushWarnings(self, offendingFunctions=None): + """ + Remove stored warnings from the list of captured warnings and return + them. + + @param offendingFunctions: If C{None}, all warnings issued during the + currently running test will be flushed. Otherwise, only warnings + which I{point} to a function included in this list will be flushed. + All warnings include a filename and source line number; if these parts of a warning point to a source line which is part of a function, then the warning I{points} to that function. - @type offendingFunctions: L{NoneType} or L{list} of functions or methods. + @type offendingFunctions: C{NoneType} or L{list} of functions or methods. @raise ValueError: If C{offendingFunctions} is not C{None} and includes - an object which is not a L{FunctionType} or L{MethodType} instance. + an object which is not a L{types.FunctionType} or + L{types.MethodType} instance. @return: A C{list}, each element of which is a C{dict} giving information about one warning which was flushed by this call. The @@ -941,102 +860,444 @@ raise ValueError("%r is not a function or method" % ( aFunction,)) - # inspect.getabsfile(aFunction) sometimes returns a - # filename which disagrees with the filename the warning - # system generates. This seems to be because a - # function's code object doesn't deal with source files - # being renamed. inspect.getabsfile(module) seems - # better (or at least agrees with the warning system - # more often), and does some normalization for us which - # is desirable. inspect.getmodule() is attractive, but - # somewhat broken in Python < 2.6. See Python bug 4845. - aModule = sys.modules[aFunction.__module__] - filename = inspect.getabsfile(aModule) + # inspect.getabsfile(aFunction) sometimes returns a + # filename which disagrees with the filename the warning + # system generates. This seems to be because a + # function's code object doesn't deal with source files + # being renamed. inspect.getabsfile(module) seems + # better (or at least agrees with the warning system + # more often), and does some normalization for us which + # is desirable. inspect.getmodule() is attractive, but + # somewhat broken in Python < 2.6. See Python bug 4845. + aModule = sys.modules[aFunction.__module__] + filename = inspect.getabsfile(aModule) + + if filename != os.path.normcase(aWarning.filename): + continue + lineStarts = list(_findlinestarts(aFunction.func_code)) + first = lineStarts[0][1] + last = lineStarts[-1][1] + if not (first <= aWarning.lineno <= last): + continue + # The warning points to this function, flush it and move on + # to the next warning. + toFlush.append(aWarning) + break + # Remove everything which is being flushed. + map(self._warnings.remove, toFlush) + + return [ + {'message': w.message, 'category': w.category, + 'filename': w.filename, 'lineno': w.lineno} + for w in toFlush] + + + def callDeprecated(self, version, f, *args, **kwargs): + """ + Call a function that should have been deprecated at a specific version + and in favor of a specific alternative, and assert that it was thusly + deprecated. + + @param version: A 2-sequence of (since, replacement), where C{since} is + a the first L{version} that C{f} + should have been deprecated since, and C{replacement} is a suggested + replacement for the deprecated functionality, as described by + L{twisted.python.deprecate.deprecated}. If there is no suggested + replacement, this parameter may also be simply a + L{version} by itself. + + @param f: The deprecated function to call. + + @param args: The arguments to pass to C{f}. + + @param kwargs: The keyword arguments to pass to C{f}. + + @return: Whatever C{f} returns. + + @raise: Whatever C{f} raises. If any exception is + raised by C{f}, though, no assertions will be made about emitted + deprecations. + + @raise FailTest: if no warnings were emitted by C{f}, or if the + L{DeprecationWarning} emitted did not produce the canonical + please-use-something-else message that is standard for Twisted + deprecations according to the given version and replacement. + """ + result = f(*args, **kwargs) + warningsShown = self.flushWarnings([self.callDeprecated]) + try: + info = list(version) + except TypeError: + since = version + replacement = None + else: + [since, replacement] = info + + if len(warningsShown) == 0: + self.fail('%r is not deprecated.' % (f,)) + + observedWarning = warningsShown[0]['message'] + expectedWarning = getDeprecationWarningString( + f, since, replacement=replacement) + self.assertEqual(expectedWarning, observedWarning) + + return result + + + def mktemp(self): + """ + Returns a unique name that may be used as either a temporary directory + or filename. + + @note: you must call os.mkdir on the value returned from this method if + you wish to use it as a directory! + """ + MAX_FILENAME = 32 # some platforms limit lengths of filenames + base = os.path.join(self.__class__.__module__[:MAX_FILENAME], + self.__class__.__name__[:MAX_FILENAME], + self._testMethodName[:MAX_FILENAME]) + if not os.path.exists(base): + os.makedirs(base) + dirname = tempfile.mkdtemp('', '', base) + return os.path.join(dirname, 'temp') + + + def _getSuppress(self): + """ + Returns any warning suppressions set for this test. Checks on the + instance first, then the class, then the module, then packages. As + soon as it finds something with a C{suppress} attribute, returns that. + Returns any empty list (i.e. suppress no warnings) if it cannot find + anything. See L{TestCase} docstring for more details. + """ + return util.acquireAttribute(self._parents, 'suppress', []) + + + def _getSkipReason(self, method, skip): + """ + Return the reason to use for skipping a test method. + + @param method: The method which produced the skip. + @param skip: A L{SkipTest} instance raised by C{method}. + """ + if len(skip.args) > 0: + return skip.args[0] + + warnAboutFunction( + method, + "Do not raise unittest.SkipTest with no arguments! Give a reason " + "for skipping tests!") + return skip + + + def _run(self, suppress, todo, method, result): + """ + Run a single method, either a test method or fixture. + + @param suppress: Any warnings to suppress, as defined by the C{suppress} + attribute on this method, test case, or the module it is defined in. + + @param todo: Any expected failure or failures, as defined by the C{todo} + attribute on this method, test case, or the module it is defined in. + + @param method: The method to run. + + @param result: The TestResult instance to which to report results. + + @return: C{True} if the method fails and no further method/fixture calls + should be made, C{False} otherwise. + """ + try: + # XXX runWithWarningsSuppressed is from twisted.internet, involves + # Deferreds, we need a synchronous-only version probably. + utils.runWithWarningsSuppressed(suppress, method) + except SkipTest as e: + result.addSkip(self, self._getSkipReason(method, e)) + except: + reason = failure.Failure() + if todo is None or not todo.expected(reason): + if reason.check(self.failureException): + addResult = result.addFailure + else: + addResult = result.addError + addResult(self, reason) + else: + result.addExpectedFailure(self, reason, todo) + else: + return False + return True + + + def _runFixturesAndTest(self, result): + """ + Run C{setUp}, a test method, test cleanups, and C{tearDown}. + + @param result: The TestResult instance to which to report results. + """ + suppress = self._getSuppress() + try: + if self._run(suppress, None, self.setUp, result): + return + + todo = self.getTodo() + method = getattr(self, self._testMethodName) + if self._run(suppress, todo, method, result): + return + finally: + self._runCleanups(result) + + if todo: + result.addUnexpectedSuccess(self, todo) + + if self._run(suppress, None, self.tearDown, result): + return + + passed = True + for error in self._observer.getErrors(): + result.addError(self, error) + passed = False + self._observer.flushErrors() + self._removeObserver() + + if passed and not todo: + result.addSuccess(self) + + + def _runCleanups(self, result): + """ + Synchronously run any cleanups which have been added. + """ + while len(self._cleanups) > 0: + f, args, kwargs = self._cleanups.pop() + try: + f(*args, **kwargs) + except: + f = failure.Failure() + result.addError(self, f) + + + def _installObserver(self): + self._observer = _logObserver + self._observer._add() + + + def _removeObserver(self): + self._observer._remove() + + + +class TestCase(SynchronousTestCase): + """ + A unit test. The atom of the unit testing universe. + + This class extends L{SynchronousTestCase} which extends C{unittest.TestCase} + from the standard library. The main feature is the ability to return + C{Deferred}s from tests and fixture methods and to have the suite wait for + those C{Deferred}s to fire. + + @ivar timeout: A real number of seconds. If set, the test will + raise an error if it takes longer than C{timeout} seconds. + If not set, util.DEFAULT_TIMEOUT_DURATION is used. + """ + implements(itrial.ITestCase) + + def __init__(self, methodName='runTest'): + """ + Construct an asynchronous test case for C{methodName}. + + @param methodName: The name of a method on C{self}. This method should + be a unit test. That is, it should be a short method that calls some of + the assert* methods. If C{methodName} is unspecified, L{runTest} will + be used as the test method. This is mostly useful for testing Trial. + """ + super(TestCase, self).__init__(methodName) + + + def _run(self, methodName, result): + from twisted.internet import reactor + timeout = self.getTimeout() + def onTimeout(d): + e = defer.TimeoutError("%r (%s) still running at %s secs" + % (self, methodName, timeout)) + f = failure.Failure(e) + # try to errback the deferred that the test returns (for no gorram + # reason) (see issue1005 and test_errorPropagation in + # test_deferred) + try: + d.errback(f) + except defer.AlreadyCalledError: + # if the deferred has been called already but the *back chain + # is still unfinished, crash the reactor and report timeout + # error ourself. + reactor.crash() + self._timedOut = True # see self._wait + todo = self.getTodo() + if todo is not None and todo.expected(f): + result.addExpectedFailure(self, f, todo) + else: + result.addError(self, f) + onTimeout = utils.suppressWarnings( + onTimeout, util.suppress(category=DeprecationWarning)) + method = getattr(self, methodName) + d = defer.maybeDeferred( + utils.runWithWarningsSuppressed, self._getSuppress(), method) + call = reactor.callLater(timeout, onTimeout, d) + d.addBoth(lambda x : call.active() and call.cancel() or x) + return d + + + def __call__(self, *args, **kwargs): + return self.run(*args, **kwargs) + + + def deferSetUp(self, ignored, result): + d = self._run('setUp', result) + d.addCallbacks(self.deferTestMethod, self._ebDeferSetUp, + callbackArgs=(result,), + errbackArgs=(result,)) + return d + + + def _ebDeferSetUp(self, failure, result): + if failure.check(SkipTest): + result.addSkip(self, self._getSkipReason(self.setUp, failure.value)) + else: + result.addError(self, failure) + if failure.check(KeyboardInterrupt): + result.stop() + return self.deferRunCleanups(None, result) + + + def deferTestMethod(self, ignored, result): + d = self._run(self._testMethodName, result) + d.addCallbacks(self._cbDeferTestMethod, self._ebDeferTestMethod, + callbackArgs=(result,), + errbackArgs=(result,)) + d.addBoth(self.deferRunCleanups, result) + d.addBoth(self.deferTearDown, result) + return d + + + def _cbDeferTestMethod(self, ignored, result): + if self.getTodo() is not None: + result.addUnexpectedSuccess(self, self.getTodo()) + else: + self._passed = True + return ignored + + + def _ebDeferTestMethod(self, f, result): + todo = self.getTodo() + if todo is not None and todo.expected(f): + result.addExpectedFailure(self, f, todo) + elif f.check(self.failureException, FailTest): + result.addFailure(self, f) + elif f.check(KeyboardInterrupt): + result.addError(self, f) + result.stop() + elif f.check(SkipTest): + result.addSkip( + self, + self._getSkipReason(getattr(self, self._testMethodName), f.value)) + else: + result.addError(self, f) + + + def deferTearDown(self, ignored, result): + d = self._run('tearDown', result) + d.addErrback(self._ebDeferTearDown, result) + return d - if filename != os.path.normcase(aWarning.filename): - continue - lineStarts = list(_findlinestarts(aFunction.func_code)) - first = lineStarts[0][1] - last = lineStarts[-1][1] - if not (first <= aWarning.lineno <= last): - continue - # The warning points to this function, flush it and move on - # to the next warning. - toFlush.append(aWarning) - break - # Remove everything which is being flushed. - map(self._warnings.remove, toFlush) - return [ - {'message': w.message, 'category': w.category, - 'filename': w.filename, 'lineno': w.lineno} - for w in toFlush] + def _ebDeferTearDown(self, failure, result): + result.addError(self, failure) + if failure.check(KeyboardInterrupt): + result.stop() + self._passed = False - def addCleanup(self, f, *args, **kwargs): + def deferRunCleanups(self, ignored, result): """ - Add the given function to a list of functions to be called after the - test has run, but before C{tearDown}. + Run any scheduled cleanups and report errors (if any to the result + object. + """ + d = self._runCleanups() + d.addCallback(self._cbDeferRunCleanups, result) + return d - Functions will be run in reverse order of being added. This helps - ensure that tear down complements set up. - The function C{f} may return a Deferred. If so, C{TestCase} will wait - until the Deferred has fired before proceeding to the next function. - """ - self._cleanups.append((f, args, kwargs)) + def _cbDeferRunCleanups(self, cleanupResults, result): + for flag, failure in cleanupResults: + if flag == defer.FAILURE: + result.addError(self, failure) + if failure.check(KeyboardInterrupt): + result.stop() + self._passed = False - def callDeprecated(self, version, f, *args, **kwargs): - """ - Call a function that should have been deprecated at a specific version - and in favor of a specific alternative, and assert that it was thusly - deprecated. + def _cleanUp(self, result): + try: + clean = util._Janitor(self, result).postCaseCleanup() + if not clean: + self._passed = False + except: + result.addError(self, failure.Failure()) + self._passed = False + for error in self._observer.getErrors(): + result.addError(self, error) + self._passed = False + self.flushLoggedErrors() + self._removeObserver() + if self._passed: + result.addSuccess(self) - @param version: A 2-sequence of (since, replacement), where C{since} is - a the first L{version} that C{f} - should have been deprecated since, and C{replacement} is a suggested - replacement for the deprecated functionality, as described by - L{twisted.python.deprecate.deprecated}. If there is no suggested - replacement, this parameter may also be simply a - L{version} by itself. - @param f: The deprecated function to call. + def _classCleanUp(self, result): + try: + util._Janitor(self, result).postClassCleanup() + except: + result.addError(self, failure.Failure()) - @param args: The arguments to pass to C{f}. - @param kwargs: The keyword arguments to pass to C{f}. + def _makeReactorMethod(self, name): + """ + Create a method which wraps the reactor method C{name}. The new + method issues a deprecation warning and calls the original. + """ + def _(*a, **kw): + warnings.warn("reactor.%s cannot be used inside unit tests. " + "In the future, using %s will fail the test and may " + "crash or hang the test run." + % (name, name), + stacklevel=2, category=DeprecationWarning) + return self._reactorMethods[name](*a, **kw) + return _ - @return: Whatever C{f} returns. - @raise: Whatever C{f} raises. If any exception is - raised by C{f}, though, no assertions will be made about emitted - deprecations. + def _deprecateReactor(self, reactor): + """ + Deprecate C{iterate}, C{crash} and C{stop} on C{reactor}. That is, + each method is wrapped in a function that issues a deprecation + warning, then calls the original. - @raise FailTest: if no warnings were emitted by C{f}, or if the - L{DeprecationWarning} emitted did not produce the canonical - please-use-something-else message that is standard for Twisted - deprecations according to the given version and replacement. + @param reactor: The Twisted reactor. """ - result = f(*args, **kwargs) - warningsShown = self.flushWarnings([self.callDeprecated]) - try: - info = list(version) - except TypeError: - since = version - replacement = None - else: - [since, replacement] = info + self._reactorMethods = {} + for name in ['crash', 'iterate', 'stop']: + self._reactorMethods[name] = getattr(reactor, name) + setattr(reactor, name, self._makeReactorMethod(name)) - if len(warningsShown) == 0: - self.fail('%r is not deprecated.' % (f,)) - observedWarning = warningsShown[0]['message'] - expectedWarning = getDeprecationWarningString( - f, since, replacement=replacement) - self.assertEqual(expectedWarning, observedWarning) + def _undeprecateReactor(self, reactor): + """ + Restore the deprecated reactor methods. Undoes what + L{_deprecateReactor} did. - return result + @param reactor: The Twisted reactor. + """ + for name, method in self._reactorMethods.iteritems(): + setattr(reactor, name, method) + self._reactorMethods = {} def _runCleanups(self): @@ -1054,120 +1315,41 @@ return util._runSequentially(callables) - def patch(self, obj, attribute, value): - """ - Monkey patch an object for the duration of the test. - - The monkey patch will be reverted at the end of the test using the - L{addCleanup} mechanism. - - The L{MonkeyPatcher} is returned so that users can restore and - re-apply the monkey patch within their tests. - - @param obj: The object to monkey patch. - @param attribute: The name of the attribute to change. - @param value: The value to set the attribute to. - @return: A L{monkey.MonkeyPatcher} object. - """ - monkeyPatch = monkey.MonkeyPatcher((obj, attribute, value)) - monkeyPatch.patch() - self.addCleanup(monkeyPatch.restore) - return monkeyPatch - - - def runTest(self): - """ - If no C{methodName} argument is passed to the constructor, L{run} will - treat this method as the thing with the actual test inside. - """ - - - def run(self, result): + def _runFixturesAndTest(self, result): """ - Run the test case, storing the results in C{result}. - - First runs C{setUp} on self, then runs the test method (defined in the - constructor), then runs C{tearDown}. Any of these may return - L{Deferred}s. After they complete, does some reactor cleanup. + Really run C{setUp}, the test method, and C{tearDown}. Any of these may + return L{Deferred}s. After they complete, do some reactor cleanup. @param result: A L{TestResult} object. """ - log.msg("--> %s <--" % (self.id())) from twisted.internet import reactor - new_result = itrial.IReporter(result, None) - if new_result is None: - result = PyUnitResultAdapter(result) - else: - result = new_result + self._deprecateReactor(reactor) self._timedOut = False - result.startTest(self) - if self.getSkip(): # don't run test methods that are marked as .skip - result.addSkip(self, self.getSkip()) - result.stopTest(self) - return - self._installObserver() - - # All the code inside runThunk will be run such that warnings emitted - # by it will be collected and retrievable by flushWarnings. - def runThunk(): - self._passed = False - self._deprecateReactor(reactor) + try: + d = self.deferSetUp(None, result) try: - d = self.deferSetUp(None, result) - try: - self._wait(d) - finally: - self._cleanUp(result) - self._classCleanUp(result) + self._wait(d) finally: - self._undeprecateReactor(reactor) - - self._warnings = [] - _collectWarnings(self._warnings.append, runThunk) + self._cleanUp(result) + self._classCleanUp(result) + finally: + self._undeprecateReactor(reactor) - # Any collected warnings which the test method didn't flush get - # re-emitted so they'll be logged or show up on stdout or whatever. - for w in self.flushWarnings(): - try: - warnings.warn_explicit(**w) - except: - result.addError(self, failure.Failure()) - result.stopTest(self) + def addCleanup(self, f, *args, **kwargs): + """ + Extend the base cleanup feature with support for cleanup functions which + return Deferreds. + If the function C{f} returns a Deferred, C{TestCase} will wait until the + Deferred has fired before proceeding to the next function. + """ + return super(TestCase, self).addCleanup(f, *args, **kwargs) - def _getReason(self, f): - if len(f.value.args) > 0: - reason = f.value.args[0] - else: - warnings.warn(("Do not raise unittest.SkipTest with no " - "arguments! Give a reason for skipping tests!"), - stacklevel=2) - reason = f - return reason - def getSkip(self): - """ - Return the skip reason set on this test, if any is set. Checks on the - instance first, then the class, then the module, then packages. As - soon as it finds something with a C{skip} attribute, returns that. - Returns C{None} if it cannot find anything. See L{TestCase} docstring - for more details. - """ - return util.acquireAttribute(self._parents, 'skip', None) + def getSuppress(self): + return self._getSuppress() - def getTodo(self): - """ - Return a L{Todo} object if the test is marked todo. Checks on the - instance first, then the class, then the module, then packages. As - soon as it finds something with a C{todo} attribute, returns that. - Returns C{None} if it cannot find anything. See L{TestCase} docstring - for more details. - """ - todo = util.acquireAttribute(self._parents, 'todo', None) - if todo is None: - return None - return makeTodo(todo) def getTimeout(self): """ @@ -1190,16 +1372,6 @@ category=DeprecationWarning) return util.DEFAULT_TIMEOUT_DURATION - def getSuppress(self): - """ - Returns any warning suppressions set for this test. Checks on the - instance first, then the class, then the module, then packages. As - soon as it finds something with a C{suppress} attribute, returns that. - Returns any empty list (i.e. suppress no warnings) if it cannot find - anything. See L{TestCase} docstring for more details. - """ - return util.acquireAttribute(self._parents, 'suppress', []) - def visit(self, visitor): """ @@ -1217,22 +1389,6 @@ visitor(self) - def mktemp(self): - """Returns a unique name that may be used as either a temporary - directory or filename. - - @note: you must call os.mkdir on the value returned from this - method if you wish to use it as a directory! - """ - MAX_FILENAME = 32 # some platforms limit lengths of filenames - base = os.path.join(self.__class__.__module__[:MAX_FILENAME], - self.__class__.__name__[:MAX_FILENAME], - self._testMethodName[:MAX_FILENAME]) - if not os.path.exists(base): - os.makedirs(base) - dirname = tempfile.mkdtemp('', '', base) - return os.path.join(dirname, 'temp') - def _wait(self, d, running=_wait_is_running): """Take a Deferred that only ever callbacks. Block until it happens. """ @@ -1296,6 +1452,7 @@ running.pop() + class UnsupportedTrialFeature(Exception): """A feature of twisted.trial was used that pyunit cannot support.""" @@ -1615,6 +1772,7 @@ for methodName in _assertions: globals()[methodName] = _deprecate(methodName) +del methodName -__all__ = ['TestCase', 'FailTest', 'SkipTest'] +__all__ = ['SynchronousTestCase', 'TestCase', 'FailTest', 'SkipTest']