r47243 - Merge forward

hawkowl-TA+aISz0psMTMxyoc4vAAJOcrHinNvQL0E9HWUfgJXw@public.gmane.org Thu, 14 Apr 2016 20:22:24 -0600 (MDT)
Newsgroups gmane.comp.python.twisted.commits
Message-ID <[email protected]>
Author: hawkowl
Date: Thu Apr 14 20:22:18 2016
New Revision: 47243

Added:
   branches/moar-windows-8025-7/twisted/topfiles/8025.misc
Modified:
   branches/moar-windows-8025-7/.gitignore
   branches/moar-windows-8025-7/twisted/internet/_dumbwin32proc.py
   branches/moar-windows-8025-7/twisted/internet/_pollingfile.py
   branches/moar-windows-8025-7/twisted/internet/_win32stdio.py
   branches/moar-windows-8025-7/twisted/internet/test/_win32ifaces.py
   branches/moar-windows-8025-7/twisted/internet/test/process_cli.py
   branches/moar-windows-8025-7/twisted/internet/test/test_tcp.py
   branches/moar-windows-8025-7/twisted/internet/test/test_win32events.py
   branches/moar-windows-8025-7/twisted/internet/win32eventreactor.py
   branches/moar-windows-8025-7/twisted/logger/test/test_stdlib.py
   branches/moar-windows-8025-7/twisted/python/dist3.py
   branches/moar-windows-8025-7/twisted/python/filepath.py
   branches/moar-windows-8025-7/twisted/python/lockfile.py
   branches/moar-windows-8025-7/twisted/python/log.py
   branches/moar-windows-8025-7/twisted/python/test/test_deprecate.py
   branches/moar-windows-8025-7/twisted/python/zippath.py
   branches/moar-windows-8025-7/twisted/scripts/_twistw.py
   branches/moar-windows-8025-7/twisted/scripts/trial.py
   branches/moar-windows-8025-7/twisted/test/process_stdinreader.py
   branches/moar-windows-8025-7/twisted/test/test_compat.py
   branches/moar-windows-8025-7/twisted/test/test_internet.py
   branches/moar-windows-8025-7/twisted/test/test_lockfile.py
   branches/moar-windows-8025-7/twisted/test/test_paths.py
   branches/moar-windows-8025-7/twisted/test/test_process.py
   branches/moar-windows-8025-7/twisted/test/test_tcp.py
   branches/moar-windows-8025-7/twisted/trial/test/test_runner.py

Log:
Merge forward

Modified: branches/moar-windows-8025-7/.gitignore
==============================================================================
--- branches/moar-windows-8025-7/.gitignore	(original)
+++ branches/moar-windows-8025-7/.gitignore	Thu Apr 14 20:22:18 2016
@@ -14,3 +14,5 @@
 *~
 *.lock
 apidocs/
+.vs/
+*.pyproj
\ No newline at end of file

Modified: branches/moar-windows-8025-7/twisted/internet/_dumbwin32proc.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/internet/_dumbwin32proc.py	(original)
+++ branches/moar-windows-8025-7/twisted/internet/_dumbwin32proc.py	Thu Apr 14 20:22:18 2016
@@ -6,6 +6,8 @@
 http://isometri.cc/strips/gates_in_the_head
 """
 
+from __future__ import absolute_import, division, print_function
+
 import os
 
 # Win32 imports
@@ -26,6 +28,7 @@
 from zope.interface import implementer
 from twisted.internet.interfaces import IProcessTransport, IConsumer, IProducer
 
+from twisted.python.compat import items, _PY3, unicode
 from twisted.python.win32 import quoteArguments
 
 from twisted.internet import error
@@ -35,7 +38,7 @@
 
 def debug(msg):
     import sys
-    print msg
+    print(msg)
     sys.stdout.flush()
 
 class _Reaper(_pollingfile._PollableResource):
@@ -52,6 +55,7 @@
         return 0
 
 
+
 def _findShebang(filename):
     """
     Look for a #! line, and return the value following the #! if one exists, or
@@ -73,10 +77,12 @@
 
     @return: a str representing another filename.
     """
-    f = file(filename, 'rU')
-    if f.read(2) == '#!':
-        exe = f.readline(1024).strip('\n')
-        return exe
+    with open(filename, 'rU') as f:
+        if f.read(2) == '#!':
+            exe = f.readline(1024).strip('\n')
+            return exe
+
+
 
 def _invalidWin32App(pywinerr):
     """
@@ -97,7 +103,8 @@
 
 @implementer(IProcessTransport, IConsumer, IProducer)
 class Process(_pollingfile._PollingTimer, BaseProcess):
-    """A process that integrates with the Twisted event loop.
+    """
+    A process that integrates with the Twisted event loop.
 
     If your subprocess is a python program, you need to:
 
@@ -169,7 +176,16 @@
         env = os.environ.copy()
         env.update(environment or {})
 
+        if _PY3:
+            # Make sure all the arguments are str
+            args = [x.decode('mbcs') if isinstance(x, bytes) else x
+                    for x in args]
+
         cmdline = quoteArguments(args)
+
+        if _PY3 and isinstance(command, bytes):
+            command = command.decode('mbcs')
+
         # TODO: error detection here.  See #2787 and #4184.
         def doCreate():
             self.hProcess, self.hThread, self.pid, dwTid = win32process.CreateProcess(
@@ -177,18 +193,26 @@
         try:
             try:
                 doCreate()
-            except TypeError, e:
+            except TypeError as e:
                 # win32process.CreateProcess cannot deal with mixed
                 # str/unicode environment, so we make it all Unicode
                 if e.args != ('All dictionary items must be strings, or '
                               'all must be unicode',):
                     raise
                 newenv = {}
-                for key, value in env.items():
-                    newenv[unicode(key)] = unicode(value)
+                for key, value in items(env):
+
+                    if not isinstance(value, unicode):
+                        value = value.decode('mbcs')
+
+                    if not isinstance(key, unicode):
+                        key = key.decode('mbcs')
+
+                    newenv[key] = value
+
                 env = newenv
                 doCreate()
-        except pywintypes.error, pwte:
+        except pywintypes.error as pwte:
             if not _invalidWin32App(pwte):
                 # This behavior isn't _really_ documented, but let's make it
                 # consistent with the behavior that is documented.
@@ -210,7 +234,7 @@
                     try:
                         # Let's try again.
                         doCreate()
-                    except pywintypes.error, pwte2:
+                    except pywintypes.error as pwte2:
                         # d'oh, failed again!
                         if _invalidWin32App(pwte2):
                             raise OSError(
@@ -265,7 +289,7 @@
         """
         Write data to the process' stdin.
 
-        @type data: C{str}
+        @type data: C{bytes}
         """
         self.stdin.write(data)
 
@@ -274,7 +298,7 @@
         """
         Write data to the process' stdin.
 
-        @type data: C{list} of C{str}
+        @type data: C{list} of C{bytes}
         """
         self.stdin.writeSequence(seq)
 
@@ -291,7 +315,7 @@
         @type fd: C{int}
 
         @param data: The bytes to write.
-        @type data: C{str}
+        @type data: C{bytes}
 
         @return: C{None}
 

Modified: branches/moar-windows-8025-7/twisted/internet/_pollingfile.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/internet/_pollingfile.py	(original)
+++ branches/moar-windows-8025-7/twisted/internet/_pollingfile.py	Thu Apr 14 20:22:18 2016
@@ -7,8 +7,11 @@
 select() - this is pretty much only useful on Windows.
 """
 
+from __future__ import absolute_import, division
 
 from zope.interface import implementer
+
+from twisted.python.compat import unicode
 from twisted.internet.interfaces import IConsumer, IPushProducer
 
 
@@ -128,7 +131,7 @@
                 finished = 1
                 break
 
-        dataBuf = ''.join(fullDataRead)
+        dataBuf = b''.join(fullDataRead)
         if dataBuf:
             self.receivedCallback(dataBuf)
         if finished:
@@ -272,7 +275,7 @@
                 self.writeConnectionLost()
                 return 0
             try:
-                win32file.WriteFile(self.writePipe, '', None)
+                win32file.WriteFile(self.writePipe, b'', None)
             except pywintypes.error:
                 self.writeConnectionLost()
                 return numBytesWritten

Modified: branches/moar-windows-8025-7/twisted/internet/_win32stdio.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/internet/_win32stdio.py	(original)
+++ branches/moar-windows-8025-7/twisted/internet/_win32stdio.py	Thu Apr 14 20:22:18 2016
@@ -4,13 +4,16 @@
 Windows-specific implementation of the L{twisted.internet.stdio} interface.
 """
 
+from __future__ import absolute_import, division
+
 import win32api
-import os, msvcrt
+import os
+import msvcrt
 
 from zope.interface import implementer
 
-from twisted.internet.interfaces import IHalfCloseableProtocol, ITransport, IAddress
-from twisted.internet.interfaces import IConsumer, IPushProducer
+from twisted.internet.interfaces import IHalfCloseableProtocol, ITransport
+from twisted.internet.interfaces import IConsumer, IPushProducer, IAddress
 
 from twisted.internet import _pollingfile, main
 from twisted.python.failure import Failure
@@ -83,7 +86,7 @@
         self.stdout.write(data)
 
     def writeSequence(self, seq):
-        self.stdout.write(''.join(seq))
+        self.stdout.write(b''.join(seq))
 
     def loseConnection(self):
         self.disconnecting = True
@@ -118,4 +121,3 @@
 
     def resumeProducing(self):
         self.stdin.resumeProducing()
-

Modified: branches/moar-windows-8025-7/twisted/internet/test/_win32ifaces.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/internet/test/_win32ifaces.py	(original)
+++ branches/moar-windows-8025-7/twisted/internet/test/_win32ifaces.py	Thu Apr 14 20:22:18 2016
@@ -5,6 +5,10 @@
 Windows implementation of local network interface enumeration.
 """
 
+from __future__ import absolute_import, division
+
+from twisted.python.compat import nativeString
+
 from socket import socket, AF_INET6, SOCK_STREAM
 from ctypes import (
     WinDLL, byref, create_string_buffer, c_int, c_void_p,
@@ -115,5 +119,5 @@
             byref(retBytes))
         if ret:
             raise RuntimeError("WSAAddressToString failure")
-        retList.append(string_at(addressStringBuf))
+        retList.append(nativeString(string_at(addressStringBuf)))
     return [addr for addr in retList if '%' in addr]

Modified: branches/moar-windows-8025-7/twisted/internet/test/process_cli.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/internet/test/process_cli.py	(original)
+++ branches/moar-windows-8025-7/twisted/internet/test/process_cli.py	Thu Apr 14 20:22:18 2016
@@ -1,4 +1,8 @@
-import sys, os
+from __future__ import absolute_import, division
+
+import sys
+import os
+
 try:
     # On Windows, stdout is not opened in binary mode by default,
     # so newline characters are munged on writing, interfering with
@@ -16,8 +20,8 @@
     if sys.version_info < (3, 0):
         stdout = sys.stdout
     else:
-        res = res.encode("utf8", "surrogateescape")
         stdout = sys.stdout.buffer
+        res = res.encode(sys.getfilesystemencoding(), "surrogateescape")
 
     stdout.write(res)
     stdout.flush()

Modified: branches/moar-windows-8025-7/twisted/internet/test/test_tcp.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/internet/test/test_tcp.py	(original)
+++ branches/moar-windows-8025-7/twisted/internet/test/test_tcp.py	Thu Apr 14 20:22:18 2016
@@ -1102,8 +1102,7 @@
         try:
             connect(client, (port.getHost().host, port.getHost().port))
         except socket.error as e:
-            errnum, message = e.args
-            self.assertIn(errnum, (errno.EINPROGRESS, errno.EWOULDBLOCK))
+            self.assertIn(e.errno, (errno.EINPROGRESS, errno.EWOULDBLOCK))
 
         self.runReactor(reactor)
 
@@ -1185,8 +1184,7 @@
         try:
             connect(client, (port.getHost().host, port.getHost().port))
         except socket.error as e:
-            errnum, message = e.args
-            self.assertIn(errnum, (errno.EINPROGRESS, errno.EWOULDBLOCK))
+            self.assertIn(e.errno, (errno.EINPROGRESS, errno.EWOULDBLOCK))
         self.runReactor(reactor)
         return factory.address
 

Modified: branches/moar-windows-8025-7/twisted/internet/test/test_win32events.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/internet/test/test_win32events.py	(original)
+++ branches/moar-windows-8025-7/twisted/internet/test/test_win32events.py	Thu Apr 14 20:22:18 2016
@@ -5,7 +5,10 @@
 Tests for implementations of L{IReactorWin32Events}.
 """
 
-from thread import get_ident
+try:
+    from thread import get_ident
+except ImportError:
+    from threading import get_ident
 
 try:
     import win32event

Modified: branches/moar-windows-8025-7/twisted/internet/win32eventreactor.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/internet/win32eventreactor.py	(original)
+++ branches/moar-windows-8025-7/twisted/internet/win32eventreactor.py	Thu Apr 14 20:22:18 2016
@@ -1,11 +1,11 @@
+# -*- test-case-name: twisted.internet.test.test_win32events -*-
 # Copyright (c) Twisted Matrix Laboratories.
 # See LICENSE for details.
 
-
 """
 A win32event based implementation of the Twisted main loop.
 
-This requires pywin32 (formerly win32all) or ActivePython to be installed.
+This requires pywin32 or ActivePython to be installed.
 
 To install the event loop (and you should do this before any connections,
 listeners or connectors are added)::
@@ -17,36 +17,15 @@
  1. WaitForMultipleObjects and thus the event loop can only handle 64 objects.
  2. Process running has some problems (see L{Process} docstring).
 
-
-TODO:
- 1. Event loop handling of writes is *very* problematic (this is causing failed tests).
-    Switch to doing it the correct way, whatever that means (see below).
- 2. Replace icky socket loopback waker with event based waker (use dummyEvent object)
- 3. Switch everyone to using Free Software so we don't have to deal with proprietary APIs.
-
-
-ALTERNATIVE SOLUTIONS:
- - IIRC, sockets can only be registered once. So we switch to a structure
-   like the poll() reactor, thus allowing us to deal with write events in
-   a decent fashion. This should allow us to pass tests, but we're still
-   limited to 64 events.
-
-Or:
-
- - Instead of doing a reactor, we make this an addon to the select reactor.
-   The WFMO event loop runs in a separate thread. This means no need to maintain
-   separate code for networking, 64 event limit doesn't apply to sockets,
-   we can run processes and other win32 stuff in default event loop. The
-   only problem is that we're stuck with the icky socket based waker.
-   Another benefit is that this could be extended to support >64 events
-   in a simpler manner than the previous solution.
-
-The 2nd solution is probably what will get implemented.
+For a high-performance main loop on Windows, use
+L{twisted.internet.iocpreactor.reactor.IOCPReactor}.
 """
 
-# System imports
+from __future__ import absolute_import, division
+
 import time
 import sys
+
 from threading import Thread
 from weakref import WeakKeyDictionary
 
@@ -70,9 +49,9 @@
 
 import win32gui
 
-# Twisted imports
 from twisted.internet import posixbase
 from twisted.python import log, threadable, failure
+from twisted.python.compat import keys
 from twisted.internet.interfaces import IReactorFDSet
 from twisted.internet.interfaces import IReactorWin32Events
 from twisted.internet.threads import blockingCallFromThread
@@ -177,7 +156,8 @@
 
 
     def removeReader(self, reader):
-        """Remove a Selectable for notification of data available to read.
+        """
+        Remove a Selectable for notification of data available to read.
         """
         if reader in self._reads:
             del self._events[self._reads[reader]]
@@ -191,7 +171,8 @@
 
 
     def removeWriter(self, writer):
-        """Remove a Selectable for notification of data available to write.
+        """
+        Remove a Selectable for notification of data available to write.
         """
         if writer in self._writes:
             del self._writes[writer]
@@ -205,11 +186,17 @@
 
 
     def getReaders(self):
-        return self._reads.keys()
+        """
+        Return a L{list} of all readers.
+        """
+        return keys(self._reads)
 
 
     def getWriters(self):
-        return self._writes.keys()
+        """
+        Return a L{list} of all writers.
+        """
+        return keys(self._writes)
 
 
     def doWaitForMultipleEvents(self, timeout):
@@ -225,11 +212,11 @@
 
         # If any descriptors are trying to close, try to get them out of the way
         # first.
-        for reader in self._closedAndReading.keys():
+        for reader in keys(self._closedAndReading):
             ranUserCode = True
             self._runAction('doRead', reader)
 
-        for fd in self._writes.keys():
+        for fd in self.getWriters():
             ranUserCode = True
             log.callWithLogger(fd, self._runWrite, fd)
 
@@ -245,7 +232,7 @@
             time.sleep(timeout)
             return
 
-        handles = self._events.keys() or [self.dummyEvent]
+        handles = keys(self._events) or [self.dummyEvent]
         timeout = int(timeout * 1000)
         val = MsgWaitForMultipleObjects(handles, 0, timeout, QS_ALLINPUT)
         if val == WAIT_TIMEOUT:

Modified: branches/moar-windows-8025-7/twisted/logger/test/test_stdlib.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/logger/test/test_stdlib.py	(original)
+++ branches/moar-windows-8025-7/twisted/logger/test/test_stdlib.py	Thu Apr 14 20:22:18 2016
@@ -5,7 +5,10 @@
 Test cases for L{twisted.logger._format}.
 """
 
+from __future__ import absolute_import, division
+
 import sys
+
 from io import BytesIO, TextIOWrapper
 import logging as py_logging
 from inspect import getsourcefile
@@ -236,7 +239,7 @@
     stream = output
     template = py_logging.BASIC_FORMAT
     if _PY3:
-        stream = TextIOWrapper(output, encoding="utf-8")
+        stream = TextIOWrapper(output, encoding="utf-8", newline="\n")
     formatter = py_logging.Formatter(template)
     handler = py_logging.StreamHandler(stream)
     handler.setFormatter(formatter)

Modified: branches/moar-windows-8025-7/twisted/python/dist3.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/python/dist3.py	(original)
+++ branches/moar-windows-8025-7/twisted/python/dist3.py	Thu Apr 14 20:22:18 2016
@@ -65,12 +65,15 @@
     "twisted.cred.test.__init__",
     "twisted.internet.__init__",
     "twisted.internet._baseprocess",
+    "twisted.internet._dumbwin32proc",
     "twisted.internet._glibbase",
     "twisted.internet._newtls",
+    "twisted.internet._pollingfile",
     "twisted.internet._posixstdio",
     "twisted.internet._posixserialport",
     "twisted.internet._signals",
     "twisted.internet._win32serialport",
+    "twisted.internet._win32stdio",
     "twisted.internet.abstract",
     "twisted.internet.address",
     "twisted.internet.base",
@@ -106,6 +109,7 @@
     "twisted.internet.udp",
     "twisted.internet.unix",
     "twisted.internet.utils",
+    "twisted.internet.win32eventreactor",
     "twisted.logger.__init__",
     "twisted.logger._buffer",
     "twisted.logger._file",
@@ -213,6 +217,7 @@
     "twisted.python.zippath",
     "twisted.scripts.__init__",
     "twisted.scripts._twistd_unix",
+    "twisted.scripts._twistw",
     "twisted.scripts.trial",
     "twisted.scripts.twistd",
     "twisted.test.__init__",
@@ -298,6 +303,8 @@
     "twisted.internet.test.test_kqueuereactor",
     "twisted.internet.test.test_main",
     "twisted.internet.test.test_newtls",
+    "twisted.internet.test.test_pollingfile",
+    "twisted.internet.test.test_win32events",
     "twisted.internet.test.test_posixbase",
     "twisted.internet.test.test_posixprocess",
     "twisted.internet.test.test_process",

Modified: branches/moar-windows-8025-7/twisted/python/filepath.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/python/filepath.py	(original)
+++ branches/moar-windows-8025-7/twisted/python/filepath.py	Thu Apr 14 20:22:18 2016
@@ -1532,8 +1532,8 @@
         finally:
             f.close()
         if platform.isWindows() and exists(self.path):
-            os.unlink(self.path)
-        os.rename(sib.path, self.path)
+            os.remove(self.path)
+        os.rename(sib.path, self.asBytesMode().path)
 
 
     def __cmp__(self, other):
@@ -1708,7 +1708,8 @@
             filesystems)
         """
         try:
-            os.rename(self.path, destination.path)
+            os.rename(self._getPathAsSameTypeAs(destination.path),
+                      destination.path)
         except OSError as ose:
             if ose.errno == errno.EXDEV:
                 # man 2 rename, ubuntu linux 5.10 "breezy":

Modified: branches/moar-windows-8025-7/twisted/python/lockfile.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/python/lockfile.py	(original)
+++ branches/moar-windows-8025-7/twisted/python/lockfile.py	Thu Apr 14 20:22:18 2016
@@ -64,7 +64,7 @@
 
     # For monkeypatching in tests
     _open = open
-
+    from time import sleep as _sleep
 
     def symlink(value, filename):
         """
@@ -87,6 +87,41 @@
             f.write(value)
             f.flush()
 
+        if _PY3:
+            readValue = ""
+            iterations = 0
+            # Python 3 has no 'commit' flag for fopen, so let Windows catch
+            # up... we do this by looping and reading the file, hoping to get
+            # the correct value. It sucks, but, what can you do? Locks are
+            # global state, and as we all know, global state is BAD and EVIL.
+            # NOT EVEN ONCE - Amber
+            while readValue != value:
+                with _open(newvalname, "r") as f:
+                    readValue = f.read()
+
+                if readValue != value:
+                    iterations += 1
+
+                    # What is a reasonable number here? Well, you give an inch,
+                    # and Windows takes a mile. Sleeping for a lot of time may
+                    # waste time, but waiting for a small (0.001s) time takes
+                    # far longer on 3.5. than the 0.001s you'd expect.
+                    # 10 seconds seems like a reasonable amount of time,
+                    # assuming that file I/O on Windows can be deathly slow.
+                    if iterations > 100:
+                        try:
+                            # Try and remove the failed lock. We have given up
+                            # at  this point, so if we can't remove it, we
+                            # can't really try much.
+                            os.remove(newvalname)
+                        except:
+                            pass
+                        # We ought to play sad_trombone.mp3 here. Give up and
+                        # throw an exception.
+                        raise RuntimeError("Unable to get a lock.")
+
+                    _sleep(0.1)
+
         try:
             rename(newlinkname, filename)
         except:

Modified: branches/moar-windows-8025-7/twisted/python/log.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/python/log.py	(original)
+++ branches/moar-windows-8025-7/twisted/python/log.py	Thu Apr 14 20:22:18 2016
@@ -554,7 +554,23 @@
         }
         msgStr = _safeFormat("[%(system)s] %(text)s\n", fmtDict)
 
-        util.untilConcludes(self.write, timeStr + " " + msgStr)
+        if _PY3:
+            completedLine = timeStr + " " + msgStr
+
+            try:
+                util.untilConcludes(self.write, completedLine)
+            except UnicodeEncodeError:
+                # If we get a UnicodeDecodeError, we shouldn't really try
+                # guessing what the terminal is. Go ASCII, and if people
+                # don't like it, they should use twisted.logger.
+                completedLine = completedLine.encode(
+                    'ascii',
+                    errors='backslashreplace')
+                util.untilConcludes(self.write,
+                                    completedLine.decode('ascii'))
+        else:
+            util.untilConcludes(self.write, timeStr + " " + msgStr)
+
         util.untilConcludes(self.flush)  # Hoorj!
 
 

Modified: branches/moar-windows-8025-7/twisted/python/test/test_deprecate.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/python/test/test_deprecate.py	(original)
+++ branches/moar-windows-8025-7/twisted/python/test/test_deprecate.py	Thu Apr 14 20:22:18 2016
@@ -26,7 +26,9 @@
     deprecatedProperty,
 )
 
+from twisted.python.compat import _PY3
 from twisted.python.versions import Version
+from twisted.python.runtime import platform
 from twisted.python.filepath import FilePath
 
 from twisted.python.test import deprecatedattributes
@@ -391,6 +393,12 @@
         self.addCleanup(
             lambda: (sys.modules.clear(), sys.modules.update(modules)))
 
+        # On Windows on Python 3, most FilePath interactions produce
+        # DeprecationWarnings, so flush them here so that they don't interfere
+        # with the tests.
+        if platform.isWindows() and _PY3:
+            self.flushWarnings()
+
 
     def test_warning(self):
         """
@@ -469,7 +477,7 @@
         self.addCleanup(sys.modules.pop, module.__name__)
 
         module.callTestFunction()
-        warningsShown = self.flushWarnings()
+        warningsShown = self.flushWarnings([module.testFunction])
         warnedPath = FilePath(warningsShown[0]["filename"].encode("utf-8"))
         expectedPath = self.package.sibling(
             b'twisted_renamed_helper').child(b'module.py')

Modified: branches/moar-windows-8025-7/twisted/python/zippath.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/python/zippath.py	(original)
+++ branches/moar-windows-8025-7/twisted/python/zippath.py	Thu Apr 14 20:22:18 2016
@@ -19,6 +19,7 @@
 from twisted.python.compat import comparable, cmp
 from twisted.python.filepath import IFilePath, FilePath, AbstractFilePath
 from twisted.python.filepath import _coerceToFilesystemEncoding
+from twisted.python.filepath import UnlistableError
 
 from zope.interface import implementer
 
@@ -128,9 +129,11 @@
             if self.isdir():
                 return list(self.archive.childmap[self.pathInArchive].keys())
             else:
-                raise OSError(errno.ENOTDIR, "Leaf zip entry listed")
+                raise UnlistableError(
+                    OSError(errno.ENOTDIR, "Leaf zip entry listed"))
         else:
-            raise OSError(errno.ENOENT, "Non-existent zip entry listed")
+            raise UnlistableError(
+                OSError(errno.ENOENT, "Non-existent zip entry listed"))
 
 
     def splitext(self):

Modified: branches/moar-windows-8025-7/twisted/scripts/_twistw.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/scripts/_twistw.py	(original)
+++ branches/moar-windows-8025-7/twisted/scripts/_twistw.py	Thu Apr 14 20:22:18 2016
@@ -2,10 +2,14 @@
 # Copyright (c) Twisted Matrix Laboratories.
 # See LICENSE for details.
 
+from __future__ import absolute_import, division, print_function
+
+import sys
+import os
+
 from twisted.python import log
 from twisted.application import app, service, internet
 from twisted import copyright
-import sys, os
 
 
 
@@ -16,10 +20,11 @@
                 ]
 
     def opt_version(self):
-        """Print version information and exit.
         """
-        print 'twistd (the Twisted Windows runner) %s' % copyright.version
-        print copyright.copyright
+        Print version information and exit.
+        """
+        print('twistd (the Twisted Windows runner) %s' % copyright.version)
+        print(copyright.copyright)
         sys.exit()
 
 
@@ -45,6 +50,6 @@
         """
         service.IService(self.application).privilegedStartService()
         app.startApplication(self.application, not self.config['no_save'])
-        app.startApplication(internet.TimerService(0.1, lambda:None), 0)
+        app.startApplication(internet.TimerService(0.1, lambda: None), 0)
         self.startReactor(None, self.oldstdout, self.oldstderr)
         log.msg("Server Shut Down.")

Modified: branches/moar-windows-8025-7/twisted/scripts/trial.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/scripts/trial.py	(original)
+++ branches/moar-windows-8025-7/twisted/scripts/trial.py	Thu Apr 14 20:22:18 2016
@@ -527,13 +527,17 @@
         namedModule('readline')
     except ImportError:
         print("readline module not available")
-        sys.exc_clear()
+        if hasattr(sys, "exc_clear"):
+            # exc_clear is only available on Python 2
+            sys.exc_clear()
     for path in ('.pdbrc', 'pdbrc'):
         if os.path.exists(path):
             try:
                 rcFile = file(path, 'r')
             except IOError:
-                sys.exc_clear()
+                if hasattr(sys, "exc_clear"):
+                    # exc_clear is only available on Python 2
+                    sys.exc_clear()
             else:
                 dbg.rcLines.extend(rcFile.readlines())
     return dbg

Modified: branches/moar-windows-8025-7/twisted/test/process_stdinreader.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/test/process_stdinreader.py	(original)
+++ branches/moar-windows-8025-7/twisted/test/process_stdinreader.py	Thu Apr 14 20:22:18 2016
@@ -1,23 +1,38 @@
 # Copyright (c) Twisted Matrix Laboratories.
 # See LICENSE for details.
 
-"""Script used by twisted.test.test_process on win32."""
+"""
+Script used by twisted.test.test_process on win32.
+"""
+
+from __future__ import absolute_import, division
 
 import sys, os, msvcrt
 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
 
-
-sys.stdout.write("out\n")
-sys.stdout.flush()
-sys.stderr.write("err\n")
-sys.stderr.flush()
+# We want to write bytes directly to the output, not text, because otherwise
+# newlines get mangled. Get the buffer if it is available.
+if hasattr(sys.stdout, "buffer"):
+    stdout = sys.stdout.buffer
+else:
+    stdout = sys.stdout
+
+if hasattr(sys.stderr, "buffer"):
+    stderr = sys.stderr.buffer
+else:
+    stderr = sys.stderr
+
+stdout.write(b"out\n")
+stdout.flush()
+stderr.write(b"err\n")
+stderr.flush()
 
 data = sys.stdin.read()
 
-sys.stdout.write(data)
-sys.stdout.write("\nout\n")
-sys.stderr.write("err\n")
+stdout.write(data.encode('ascii'))
+stdout.write(b"\nout\n")
+stderr.write(b"err\n")
 
 sys.stdout.flush()
 sys.stderr.flush()

Modified: branches/moar-windows-8025-7/twisted/test/test_compat.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/test/test_compat.py	(original)
+++ branches/moar-windows-8025-7/twisted/test/test_compat.py	Thu Apr 14 20:22:18 2016
@@ -1,7 +1,6 @@
 # Copyright (c) Twisted Matrix Laboratories.
 # See LICENSE for details.
 
-
 """
 Tests for L{twisted.python.compat}.
 """
@@ -18,6 +17,7 @@
     iterbytes, intToBytes, ioType, bytesEnviron, iteritems
 )
 from twisted.python.filepath import FilePath
+from twisted.python.runtime import platform
 
 
 
@@ -751,6 +751,9 @@
 
         self.assertEqual(list(types), [bytes])
 
+    if platform.isWindows():
+        test_alwaysBytes.skip = "Environment vars are always str on Windows."
+
 
 
 class OrderedDictTests(unittest.TestCase):

Modified: branches/moar-windows-8025-7/twisted/test/test_internet.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/test/test_internet.py	(original)
+++ branches/moar-windows-8025-7/twisted/test/test_internet.py	Thu Apr 14 20:22:18 2016
@@ -957,23 +957,28 @@
 
 
 
-resolve_helper = """
-from __future__ import print_function
+resolve_helper = r"""
 import %(reactor)s
 %(reactor)s.install()
 from twisted.internet import reactor
 
-class Foo:
+import sys
+if hasattr(sys.stdout, "buffer"):
+    output = sys.stdout.buffer
+else:
+    output = sys.stdout
+
+class Foo(object):
     def __init__(self):
         reactor.callWhenRunning(self.start)
         self.timer = reactor.callLater(3, self.failed)
     def start(self):
         reactor.resolve('localhost').addBoth(self.done)
     def done(self, res):
-        print('done', res)
+        output.write(('done ' + res + '\n').encode('ascii'))
         reactor.stop()
     def failed(self):
-        print('failed')
+        output.write('failed\n')
         self.timer = None
         reactor.stop()
 f = Foo()

Modified: branches/moar-windows-8025-7/twisted/test/test_lockfile.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/test/test_lockfile.py	(original)
+++ branches/moar-windows-8025-7/twisted/test/test_lockfile.py	Thu Apr 14 20:22:18 2016
@@ -13,6 +13,7 @@
 
 from twisted.trial import unittest
 from twisted.python import lockfile
+from twisted.python.compat import _PY3
 from twisted.python.reflect import requireModule
 from twisted.python.runtime import platform
 
@@ -24,6 +25,8 @@
         skipKill = ("On windows, lockfile.kill is not implemented in the "
                     "absence of win32api and/or pywintypes.")
 
+
+
 class UtilTests(unittest.TestCase):
     """
     Tests for the helper functions used to implement L{FilesystemLock}.
@@ -91,6 +94,54 @@
             "Windows.")
 
 
+    def test_symlinkLockTimeoutWindows(self):
+        """
+        L{lockfile.symlink} on Python 3 on Windows cannot get an 'atomic' lock.
+        So, we have to fake it, and just loop until we have acquired it. If we
+        never get the correct value, we timeout.
+        """
+        name = self.mktemp()
+        class FakeOpen(object):
+            """
+            A fake open() for testing, that never returns any content and
+            throws away any writes.
+            """
+            def __init__(self, name, mode):
+                pass
+
+            def __enter__(self):
+                return self
+
+            def __exit__(self, *args, **kwargs):
+                pass
+
+            def write(self, data):
+                pass
+
+            def flush(self):
+                pass
+
+            def close(self):
+                pass
+
+            def read(self):
+                return ""
+
+        sleptFor = []
+
+        def fakeSleep(time):
+            sleptFor.append(time)
+
+        self.patch(lockfile, '_open', FakeOpen)
+        self.patch(lockfile, '_sleep', fakeSleep)
+        self.assertRaises(RuntimeError, lockfile.symlink, name, 'data')
+        self.assertEqual(round(sum(sleptFor)), 10.0)
+    if not (platform.isWindows() and _PY3):
+        test_symlinkLockTimeoutWindows.skip = (
+            "The interesting(tm) symlink timeout support is only needed on "
+            "Windows on Python 3.")
+
+
     def test_kill(self):
         """
         L{lockfile.kill} returns without error if passed the PID of a

Modified: branches/moar-windows-8025-7/twisted/test/test_paths.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/test/test_paths.py	(original)
+++ branches/moar-windows-8025-7/twisted/test/test_paths.py	Thu Apr 14 20:22:18 2016
@@ -283,6 +283,9 @@
         self.assertRaises(filepath.UnlistableError, fwp.children)
         self.assertRaises(WindowsError, fwp.children)
 
+    if _PY3:
+        test_windowsErrorExcept.skip = "This doesn't raise WindowsError anymore"
+
 
     def test_alwaysCatchOSError(self):
         """

Modified: branches/moar-windows-8025-7/twisted/test/test_process.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/test/test_process.py	(original)
+++ branches/moar-windows-8025-7/twisted/test/test_process.py	Thu Apr 14 20:22:18 2016
@@ -40,7 +40,7 @@
 from twisted.python.log import msg
 from twisted.internet import reactor, protocol, error, interfaces, defer
 from twisted.trial import unittest
-from twisted.python import util, runtime, procutils
+from twisted.python import runtime, procutils
 from twisted.python.compat import _PY3, networkString, xrange
 from twisted.python.filepath import FilePath, _asFilesystemBytes
 
@@ -2245,8 +2245,8 @@
         p.transport.closeStdin()
 
         def processEnded(ign):
-            self.assertEqual(p.errF.getvalue(), "err\nerr\n")
-            self.assertEqual(p.outF.getvalue(), "out\nhello, world\nout\n")
+            self.assertEqual(p.errF.getvalue(), b"err\nerr\n")
+            self.assertEqual(p.outF.getvalue(), b"out\nhello, world\nout\n")
         return d.addCallback(processEnded)
 
 
@@ -2386,11 +2386,14 @@
         from twisted.internet import _dumbwin32proc
         from twisted.test import mock_win32process
         self.patch(_dumbwin32proc, "win32process", mock_win32process)
-        scriptPath = util.sibpath(__file__, "process_cmdline.py")
+        scriptPath = FilePath(__file__).sibling(b"process_cmdline.py").path
 
         d = defer.Deferred()
         processProto = TrivialProcessProtocol(d)
-        comspec = bytes(os.environ["COMSPEC"])
+        if _PY3:
+            comspec = os.environ["COMSPEC"].encode("mbcs")
+        else:
+            comspec = str(os.environ["COMSPEC"])
         cmd = [comspec, b"/c", pyExe, scriptPath]
 
         p = _dumbwin32proc.Process(reactor,
@@ -2582,8 +2585,11 @@
         """
         d = self.doit(1)
         def _check(errput):
-            if _PY3:
+            if _PY3 and not runtime.platform.isWindows():
                 self.assertIn(b'BrokenPipeError', errput)
+            elif _PY3:
+                self.assertIn(b"OSError", errput)
+                self.assertIn(b"22", errput)
             else:
                 self.assertIn(b'OSError', errput)
             if runtime.platform.getType() != 'win32':

Modified: branches/moar-windows-8025-7/twisted/test/test_tcp.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/test/test_tcp.py	(original)
+++ branches/moar-windows-8025-7/twisted/test/test_tcp.py	Thu Apr 14 20:22:18 2016
@@ -14,6 +14,8 @@
 
 from twisted.trial import unittest
 
+from twisted.python.compat import _PY3
+from twisted.python.runtime import platform
 from twisted.python.log import msg, err
 from twisted.internet import protocol, reactor, defer, interfaces
 from twisted.internet import error
@@ -22,6 +24,8 @@
 from twisted.protocols import policies
 from twisted.test.proto_helpers import AccumulatingProtocol
 
+WSAENOTSOCK = 10038
+
 
 def loopUntil(predicate, interval=0):
     """
@@ -906,7 +910,8 @@
             expected = b"".join([b"Hello Cleveland!\n",
                                 b"Goodbye", b" cruel", b" world", b"\n"])
             self.assertTrue(clientF.data == expected,
-                            "client didn't receive all the data it expected")
+                            "client didn't receive all the data it expected"
+                            "(%s!=%s)" % (clientF.data, expected))
         d = defer.gatherResults([wrappedF.onDisconnect,
                                  wrappedClientF.onDisconnect])
         return d.addCallback(check)
@@ -1138,11 +1143,18 @@
         Return the errno expected to result from writing to a closed
         platform socket handle.
         """
-        # These platforms have been seen to give EBADF:
-        #
-        #  Linux 2.4.26, Linux 2.6.15, OS X 10.4, FreeBSD 5.4
-        #  Windows 2000 SP 4, Windows XP SP 2
-        return errno.EBADF
+        if _PY3 and platform.isWindows():
+            # These platforms have been seen to give WinError 10038
+            #
+            #  Windows 10 on Python 3.4/3.5
+            return WSAENOTSOCK
+        else:
+            # These platforms have been seen to give EBADF:
+            #
+            #  Linux 2.4.26, Linux 2.6.15, OS X 10.4, FreeBSD 5.4
+            #  Windows 2000 SP 4, Windows XP SP 2
+            return errno.EBADF
+
 
 
     def test_properlyCloseFiles(self):
@@ -1363,12 +1375,16 @@
         self.factory.done = 1
         self.transport.loseConnection()
 
+
+
 class LargeBufferReaderProtocol(protocol.Protocol):
     def dataReceived(self, data):
         self.factory.len += len(data)
     def connectionLost(self, reason):
         self.factory.done = 1
 
+
+
 class LargeBufferReaderClientFactory(protocol.ClientFactory):
     def __init__(self):
         self.done = 0
@@ -1380,8 +1396,10 @@
         return p
 
 
+
 class FireOnClose(policies.ProtocolWrapper):
-    """A wrapper around a protocol that makes it fire a deferred when
+    """
+    A wrapper around a protocol that makes it fire a deferred when
     connectionLost is called.
     """
     def connectionLost(self, reason):
@@ -1389,6 +1407,7 @@
         self.factory.deferred.callback(None)
 
 
+
 class FireOnCloseFactory(policies.WrappingFactory):
     protocol = FireOnClose
 
@@ -1398,10 +1417,12 @@
 
 
 class LargeBufferTests(unittest.TestCase):
-    """Test that buffering large amounts of data works.
+    """
+    Test that buffering large amounts of data works.
     """
 
     datalen = 60*1024*1024
+
     def testWriter(self):
         f = protocol.Factory()
         f.protocol = LargeBufferWriterProtocol
@@ -1427,10 +1448,10 @@
         return d.addCallback(check)
 
 
+
 @implementer(IHalfCloseableProtocol)
 class MyHCProtocol(AccumulatingProtocol):
 
-
     readHalfClosed = False
     writeHalfClosed = False
 
@@ -1447,6 +1468,7 @@
             self.connectionLost(None)
 
 
+
 class MyHCFactory(protocol.ServerFactory):
 
     called = 0

Modified: branches/moar-windows-8025-7/twisted/trial/test/test_runner.py
==============================================================================
--- branches/moar-windows-8025-7/twisted/trial/test/test_runner.py	(original)
+++ branches/moar-windows-8025-7/twisted/trial/test/test_runner.py	Thu Apr 14 20:22:18 2016
@@ -1030,11 +1030,16 @@
             # We have to use a pyunit test, otherwise we'll get deprecation
             # warnings about using iterate() in a test.
             trialRunner.run(pyunit.TestCase('id'))
-        self.assertWarns(
-            DeprecationWarning,
+
+        f()
+        warnings = self.flushWarnings([self.test_reporterDeprecations])
+
+        self.assertEqual(warnings[0]['category'], DeprecationWarning)
+        self.assertEqual(warnings[0]['message'],
             "%s should implement done() but doesn't. Falling back to "
-            "printErrors() and friends." % reflect.qual(result.__class__),
-            __file__, f)
+            "printErrors() and friends." % reflect.qual(result.__class__))
+        self.assertEqual(warnings[0]['filename'], __file__)
+        self.assertEqual(len(warnings), 1)