From 82f6984580e1fda51e6039a8f20e178222a40988 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 12:48:33 -0500 Subject: [PATCH 01/13] win: Fix base tests to run --- tests/test_base.py | 3 ++- uvloop/_testbase.py | 13 ++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/test_base.py b/tests/test_base.py index 43760891..09d324bd 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,5 +1,4 @@ import asyncio -import fcntl import logging import os import sys @@ -683,8 +682,10 @@ def test_loop_call_later_handle_cancelled(self): self.run_loop_briefly(delay=0.05) self.assertFalse(handle.cancelled()) + @unittest.skipIf(sys.platform.startswith('win'), 'posix only test') def test_loop_std_files_cloexec(self): # See https://github.com/MagicStack/uvloop/issues/40 for details. + import fcntl for fd in {0, 1, 2}: flags = fcntl.fcntl(fd, fcntl.F_GETFD) self.assertFalse(flags & fcntl.FD_CLOEXEC) diff --git a/uvloop/_testbase.py b/uvloop/_testbase.py index 42f40185..4471463b 100644 --- a/uvloop/_testbase.py +++ b/uvloop/_testbase.py @@ -29,7 +29,6 @@ class TestCaseDict(collections.UserDict): def __init__(self, name): super().__init__() self.name = name - def __setitem__(self, key, value): if key in self.data: raise RuntimeError('duplicate test {}.{}'.format( @@ -287,12 +286,16 @@ class AIOTestCase(BaseTestCase): def setUp(self): super().setUp() - watcher = asyncio.SafeChildWatcher() - watcher.attach_loop(self.loop) - asyncio.set_child_watcher(watcher) + # No watchers on Windows + if hasattr(asyncio, 'SafeChildWatcher'): + # posix system + watcher = asyncio.SafeChildWatcher() + watcher.attach_loop(self.loop) + asyncio.set_child_watcher(watcher) def tearDown(self): - asyncio.set_child_watcher(None) + if hasattr(asyncio, 'SafeChildWatcher'): + asyncio.set_child_watcher(None) super().tearDown() def new_loop(self): From 47267c15ed0348311b13cd52952f4a8fe9aaa000 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 12:50:58 -0500 Subject: [PATCH 02/13] win: Fix setup.py to build on Windows --- setup.py | 97 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 32 deletions(-) diff --git a/setup.py b/setup.py index cb37a878..bb633ea0 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,12 @@ import os import os.path +import platform import re import shutil import subprocess import sys -if sys.platform in ('win32', 'cygwin', 'cli'): - raise RuntimeError('uvloop does not support Windows at the moment') - vi = sys.version_info if vi < (3, 5): raise RuntimeError('uvloop requires Python 3.5 or greater') @@ -216,36 +214,55 @@ def _patch_cfile(self, cfile): def build_libuv(self): env = _libuv_build_env() - # Make sure configure and friends are present in case - # we are building from a git checkout. - _libuv_autogen(env) - - # Copy the libuv tree to build/ so that its build - # products don't pollute sdist accidentally. - if os.path.exists(LIBUV_BUILD_DIR): - shutil.rmtree(LIBUV_BUILD_DIR) - shutil.copytree(LIBUV_DIR, LIBUV_BUILD_DIR) + if sys.platform == 'win32': + pypath = os.path.expandvars(os.path.join( + '%SYSTEMDRIVE%', 'Python27', 'python.exe')) + if not os.path.exists(pypath): + raise RuntimeError( + 'cannot find Python 2.7 at {!r}'.format(pypath)) + env['PYTHON'] = pypath - # Sometimes pip fails to preserve the timestamps correctly, - # in which case, make will try to run autotools again. - subprocess.run( - ['touch', 'configure.ac', 'aclocal.m4', 'configure', - 'Makefile.am', 'Makefile.in'], - cwd=LIBUV_BUILD_DIR, env=env, check=True) + arch = platform.architecture()[0] + libuv_arch = {'32bit': 'x86', '64bit': 'x64'}[arch] + subprocess.run( + ['cmd.exe', '/C', 'vcbuild.bat', libuv_arch, 'release'], + cwd=LIBUV_BUILD_DIR, env=env, check=True) - if 'LIBUV_CONFIGURE_HOST' in env: - cmd = ['./configure', '--host=' + env['LIBUV_CONFIGURE_HOST']] else: - cmd = ['./configure'] - subprocess.run( - cmd, - cwd=LIBUV_BUILD_DIR, env=env, check=True) - - j_flag = '-j{}'.format(os.cpu_count() or 1) - c_flag = "CFLAGS={}".format(env['CFLAGS']) - subprocess.run( - ['make', j_flag, c_flag], - cwd=LIBUV_BUILD_DIR, env=env, check=True) + if 'LIBUV_CONFIGURE_HOST' in env: + cmd = ['./configure', '--host=' + env['LIBUV_CONFIGURE_HOST']] + else: + cmd = ['./configure'] + subprocess.run( + cmd, + cwd=LIBUV_BUILD_DIR, env=env, check=True) + + # Make sure configure and friends are present in case + # we are building from a git checkout. + _libuv_autogen(env) + + # Copy the libuv tree to build/ so that its build + # products don't pollute sdist accidentally. + if os.path.exists(LIBUV_BUILD_DIR): + shutil.rmtree(LIBUV_BUILD_DIR) + shutil.copytree(LIBUV_DIR, LIBUV_BUILD_DIR) + + # Sometimes pip fails to preserve the timestamps correctly, + # in which case, make will try to run autotools again. + subprocess.run( + ['touch', 'configure.ac', 'aclocal.m4', 'configure', + 'Makefile.am', 'Makefile.in'], + cwd=LIBUV_BUILD_DIR, env=env, check=True) + + subprocess.run( + ['./configure'], + cwd=LIBUV_BUILD_DIR, env=env, check=True) + + j_flag = '-j{}'.format(os.cpu_count() or 1) + c_flag = "CFLAGS={}".format(env['CFLAGS']) + subprocess.run( + ['make', j_flag, c_flag], + cwd=LIBUV_BUILD_DIR, env=env, check=True) def build_extensions(self): if self.use_system_libuv: @@ -256,7 +273,12 @@ def build_extensions(self): # Support macports on Mac OS X. self.compiler.add_include_dir('/opt/local/include') else: - libuv_lib = os.path.join(LIBUV_BUILD_DIR, '.libs', 'libuv.a') + if sys.platform != 'win32': + libuv_lib = os.path.join(LIBUV_BUILD_DIR, '.libs', 'libuv.a') + else: + libuv_lib = os.path.join( + LIBUV_BUILD_DIR, 'Release', 'lib', 'libuv.lib') + if not os.path.exists(libuv_lib): self.build_libuv() if not os.path.exists(libuv_lib): @@ -267,13 +289,24 @@ def build_extensions(self): if sys.platform.startswith('linux'): self.compiler.add_library('rt') + elif sys.platform.startswith(('freebsd', 'dragonfly')): self.compiler.add_library('kvm') + elif sys.platform.startswith('sunos'): self.compiler.add_library('kstat') - + self.compiler.add_library('pthread') + elif sys.platform.startswith('win'): + self.compiler.add_library('advapi32') + self.compiler.add_library('iphlpapi') + self.compiler.add_library('psapi') + self.compiler.add_library('shell32') + self.compiler.add_library('user32') + self.compiler.add_library('userenv') + self.compiler.add_library('ws2_32') + super().build_extensions() From 3a6a329e21d02cd72f36b925e10d6c3fde8520ad Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 12:51:18 -0500 Subject: [PATCH 03/13] win: Fix uv->sys error conversion code --- uvloop/errors.pyx | 19 +++++++++++-------- uvloop/includes/stdlib.pxi | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/uvloop/errors.pyx b/uvloop/errors.pyx index d810d65e..14c4d891 100644 --- a/uvloop/errors.pyx +++ b/uvloop/errors.pyx @@ -3,13 +3,6 @@ cdef str __strerr(int errno): cdef __convert_python_error(int uverr): - # XXX Won't work for Windows: - # From libuv docs: - # Implementation detail: on Unix error codes are the - # negated errno (or -errno), while on Windows they - # are defined by libuv to arbitrary negative numbers. - cdef int oserr = -uverr - exc = OSError if uverr in (uv.UV_EACCES, uv.UV_EPERM): @@ -48,7 +41,17 @@ cdef __convert_python_error(int uverr): elif uverr == uv.UV_ETIMEDOUT: exc = TimeoutError - return exc(oserr, __strerr(oserr)) + IF UNAME_SYSNAME == "Windows": + # Translate libuv/Windows error to a posix errno + errname = uv.uv_err_name(uverr).decode() + err = getattr(errno, errname, uverr) + return exc(err, uv.uv_strerror(uverr).decode()) + ELSE: + # From libuv docs: + # Implementation detail: on Unix error codes are the + # negated errno (or -errno), while on Windows they + # are defined by libuv to arbitrary negative numbers. + return exc(-uverr, __strerr(-uverr)) cdef int __convert_socket_error(int uverr): diff --git a/uvloop/includes/stdlib.pxi b/uvloop/includes/stdlib.pxi index 01100ee0..cb8b7b62 100644 --- a/uvloop/includes/stdlib.pxi +++ b/uvloop/includes/stdlib.pxi @@ -145,8 +145,8 @@ cdef py_inf = float('inf') # Cython doesn't clean-up imported objects properly in Py3 mode, -# so we delete refs to all modules manually (except sys) -del asyncio, concurrent, collections, errno +# so we delete refs to all modules manually (except sys and errno) +del asyncio, concurrent, collections del functools, inspect, itertools, socket, os, threading del std_signal, subprocess, ssl del time, traceback, warnings, weakref From edca0686721fc830770a0085a71638c5a8c6ad04 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 12:51:55 -0500 Subject: [PATCH 04/13] win: Split system.pxd into posix/windows includes --- uvloop/includes/posix.pxi | 74 +++++++++++++++++++++++++++++++++++ uvloop/includes/system.pxd | 78 ++----------------------------------- uvloop/includes/windows.pxi | 40 +++++++++++++++++++ 3 files changed, 118 insertions(+), 74 deletions(-) create mode 100644 uvloop/includes/posix.pxi create mode 100644 uvloop/includes/windows.pxi diff --git a/uvloop/includes/posix.pxi b/uvloop/includes/posix.pxi new file mode 100644 index 00000000..65120081 --- /dev/null +++ b/uvloop/includes/posix.pxi @@ -0,0 +1,74 @@ +cdef extern from "arpa/inet.h" nogil: + + int ntohl(int) + int htonl(int) + int ntohs(int) + + +cdef extern from "sys/socket.h" nogil: + + struct sockaddr: + unsigned short sa_family + char sa_data[14] + + struct addrinfo: + int ai_flags + int ai_family + int ai_socktype + int ai_protocol + size_t ai_addrlen + sockaddr* ai_addr + char* ai_canonname + addrinfo* ai_next + + struct sockaddr_in: + unsigned short sin_family + unsigned short sin_port + # ... + + struct sockaddr_in6: + unsigned short sin6_family + unsigned short sin6_port + unsigned long sin6_flowinfo + # ... + unsigned long sin6_scope_id + + struct sockaddr_storage: + unsigned short ss_family + # ... + + const char *gai_strerror(int errcode) + + int socketpair(int domain, int type, int protocol, int socket_vector[2]) + + int setsockopt(int socket, int level, int option_name, + const void *option_value, int option_len) + + +cdef extern from "unistd.h" nogil: + + ssize_t write(int fd, const void *buf, size_t count) + void _exit(int status) + + +cdef extern from "pthread.h" nogil: + + int pthread_atfork( + void (*prepare)() nogil, + void (*parent)() nogil, + void (*child)() nogil) + + +cdef extern from "includes/compat.h" nogil: + + cdef int EWOULDBLOCK + + cdef int PLATFORM_IS_APPLE + cdef int PLATFORM_IS_LINUX + + struct epoll_event: + # We don't use the fields + pass + + int EPOLL_CTL_DEL + int epoll_ctl(int epfd, int op, int fd, epoll_event *event) diff --git a/uvloop/includes/system.pxd b/uvloop/includes/system.pxd index 65120081..1da7bf27 100644 --- a/uvloop/includes/system.pxd +++ b/uvloop/includes/system.pxd @@ -1,74 +1,4 @@ -cdef extern from "arpa/inet.h" nogil: - - int ntohl(int) - int htonl(int) - int ntohs(int) - - -cdef extern from "sys/socket.h" nogil: - - struct sockaddr: - unsigned short sa_family - char sa_data[14] - - struct addrinfo: - int ai_flags - int ai_family - int ai_socktype - int ai_protocol - size_t ai_addrlen - sockaddr* ai_addr - char* ai_canonname - addrinfo* ai_next - - struct sockaddr_in: - unsigned short sin_family - unsigned short sin_port - # ... - - struct sockaddr_in6: - unsigned short sin6_family - unsigned short sin6_port - unsigned long sin6_flowinfo - # ... - unsigned long sin6_scope_id - - struct sockaddr_storage: - unsigned short ss_family - # ... - - const char *gai_strerror(int errcode) - - int socketpair(int domain, int type, int protocol, int socket_vector[2]) - - int setsockopt(int socket, int level, int option_name, - const void *option_value, int option_len) - - -cdef extern from "unistd.h" nogil: - - ssize_t write(int fd, const void *buf, size_t count) - void _exit(int status) - - -cdef extern from "pthread.h" nogil: - - int pthread_atfork( - void (*prepare)() nogil, - void (*parent)() nogil, - void (*child)() nogil) - - -cdef extern from "includes/compat.h" nogil: - - cdef int EWOULDBLOCK - - cdef int PLATFORM_IS_APPLE - cdef int PLATFORM_IS_LINUX - - struct epoll_event: - # We don't use the fields - pass - - int EPOLL_CTL_DEL - int epoll_ctl(int epfd, int op, int fd, epoll_event *event) +IF UNAME_SYSNAME == "Windows": + include "windows.pxi" +ELSE: + include "posix.pxi" diff --git a/uvloop/includes/windows.pxi b/uvloop/includes/windows.pxi new file mode 100644 index 00000000..1864bd45 --- /dev/null +++ b/uvloop/includes/windows.pxi @@ -0,0 +1,40 @@ +cdef extern from "Winsock2.h" nogil: + + int ntohl(int) + int htonl(int) + int ntohs(int) + + struct sockaddr: + unsigned short sa_family + char sa_data[14] + + struct addrinfo: + int ai_flags + int ai_family + int ai_socktype + int ai_protocol + size_t ai_addrlen + sockaddr* ai_addr + char* ai_canonname + addrinfo* ai_next + + struct sockaddr_in: + unsigned short sin_family + unsigned short sin_port + # ... + + struct sockaddr_in6: + unsigned short sin6_family + unsigned short sin6_port + unsigned long sin6_flowinfo + # ... + unsigned long sin6_scope_id + + struct sockaddr_storage: + unsigned short ss_family + # ... + + const char *gai_strerror(int errcode) + + int setsockopt(int socket, int level, int option_name, + const void *option_value, int option_len) From 9a85c1431cd31f20b35eee946a0d01b7f6204ec6 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 12:52:36 -0500 Subject: [PATCH 05/13] win: Fix Poll handle to accept Windows sockets --- uvloop/handles/poll.pyx | 5 +++-- uvloop/includes/uv.pxd | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/uvloop/handles/poll.pyx b/uvloop/handles/poll.pyx index 8640eced..b4db1e3b 100644 --- a/uvloop/handles/poll.pyx +++ b/uvloop/handles/poll.pyx @@ -11,8 +11,9 @@ cdef class UVPoll(UVHandle): self._abort_init() raise MemoryError() - err = uv.uv_poll_init(self._loop.uvloop, - self._handle, fd) + err = uv.uv_poll_init_socket(self._loop.uvloop, + self._handle, + fd) if err < 0: self._abort_init() raise convert_error(err) diff --git a/uvloop/includes/uv.pxd b/uvloop/includes/uv.pxd index 9defb62d..df84d41f 100644 --- a/uvloop/includes/uv.pxd +++ b/uvloop/includes/uv.pxd @@ -4,7 +4,7 @@ from posix.types cimport gid_t, uid_t from . cimport system -cdef extern from "includes/compat.h": +cdef extern from "includes/compat.h" nogil: # Member of uv_poll_event, in compat.h for compatibility # with libuv < v1.9.0 cdef int UV_DISCONNECT @@ -347,7 +347,6 @@ cdef extern from "uv.h" nogil: # Polling - int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, uv_os_sock_t socket) int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) From c2defd035911bccdf76b28e230eafe523135c265 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 12:53:20 -0500 Subject: [PATCH 06/13] win: Use socket.dup() on Windows --- uvloop/loop.pyx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index ab9588ef..04f30af7 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -58,6 +58,17 @@ cdef _is_sock_dgram(sock_type): return (sock_type & 0xF) == uv.SOCK_DGRAM +cdef __dup(sock): + # cross-platform duping + IF UNAME_SYSNAME == "Windows": + dup_sock = sock.dup() + fileno = dup_sock.fileno() + dup_sock.detach() + return fileno + ELSE: + return os_dup(sock.fileno()) + + cdef isfuture(obj): if aio_isfuture is None: return isinstance(obj, aio_Future) From 5809486d024553d67f56a075b1d8da514d6462c7 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 12:53:45 -0500 Subject: [PATCH 07/13] win: Don't do first-try-write on Windows --- uvloop/handles/stream.pyx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/uvloop/handles/stream.pyx b/uvloop/handles/stream.pyx index 6619b30f..1da79b2d 100644 --- a/uvloop/handles/stream.pyx +++ b/uvloop/handles/stream.pyx @@ -311,6 +311,10 @@ cdef class UVStream(UVBaseTransport): int saved_errno int fd + IF UNAME_SYSNAME == "Windows": + # Don't need this optimization on windows. + raise NotImplementedError + if (self._handle).write_queue_size != 0: raise RuntimeError( 'UVStream._try_write called with data in uv buffers') @@ -413,6 +417,7 @@ cdef class UVStream(UVBaseTransport): int err int buf_len _StreamWriteContext ctx = None + skip_try = 0 if self._closed: # If the handle is closed, just return, it's too @@ -423,7 +428,11 @@ cdef class UVStream(UVBaseTransport): if not buf_len: return - if (self._handle).write_queue_size == 0: + IF UNAME_SYSNAME == "Windows": + skip_try = 1 + + if (not skip_try and + (self._handle).write_queue_size == 0): # libuv internal write buffers for this stream are empty. if buf_len == 1: # If we only have one piece of data to send, let's From fe0787f98785136973754d3a1d77a49032d1b384 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 12:55:00 -0500 Subject: [PATCH 08/13] win: Don't try to use pthread_atfork on Windows --- uvloop/loop.pyx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index 04f30af7..d4a95fd8 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -2743,6 +2743,10 @@ cdef void __atfork_child() nogil: cdef __install_atfork(): global __atfork_installed + + IF UNAME_SYSNAME == "Windows": + return + if __atfork_installed: return __atfork_installed = 1 From 2e937cfdb8808c638f8f8cb509857cad38d741af Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 22 Nov 2016 14:28:14 -0500 Subject: [PATCH 09/13] win: Build libuv properly on Windows --- setup.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index bb633ea0..8ca9d630 100644 --- a/setup.py +++ b/setup.py @@ -214,7 +214,24 @@ def _patch_cfile(self, cfile): def build_libuv(self): env = _libuv_build_env() + if sys.platform != 'win32': + # Make sure configure and friends are present in case + # we are building from a git checkout. + _libuv_autogen(env) + + # Copy the libuv tree to build/ so that its build + # products don't pollute sdist accidentally. + if os.path.exists(LIBUV_BUILD_DIR): + shutil.rmtree(LIBUV_BUILD_DIR) + shutil.copytree(LIBUV_DIR, LIBUV_BUILD_DIR) + if sys.platform == 'win32': + env.pop('VS120COMNTOOLS', None) + env.pop('VS110COMNTOOLS', None) + env.pop('VS100COMNTOOLS', None) + env.pop('VS90COMNTOOLS', None) + env['GYP_MSVS_VERSION'] = '2015' + pypath = os.path.expandvars(os.path.join( '%SYSTEMDRIVE%', 'Python27', 'python.exe')) if not os.path.exists(pypath): @@ -296,8 +313,6 @@ def build_extensions(self): elif sys.platform.startswith('sunos'): self.compiler.add_library('kstat') - self.compiler.add_library('pthread') - elif sys.platform.startswith('win'): self.compiler.add_library('advapi32') self.compiler.add_library('iphlpapi') @@ -307,6 +322,9 @@ def build_extensions(self): self.compiler.add_library('userenv') self.compiler.add_library('ws2_32') + if not sys.platform.startswith('win'): + self.compiler.add_library('pthread') + super().build_extensions() From be83f3db6dc47964122ed57db982593e3e616e56 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Wed, 23 Nov 2016 17:27:15 -0500 Subject: [PATCH 10/13] win: Fix testbase/tcp_server() to run when socket.AF_UNIX is n/a --- uvloop/_testbase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uvloop/_testbase.py b/uvloop/_testbase.py index 4471463b..87a833ab 100644 --- a/uvloop/_testbase.py +++ b/uvloop/_testbase.py @@ -144,7 +144,7 @@ def tcp_server(self, server_prog, *, max_clients=10): if addr is None: - if family == socket.AF_UNIX: + if hasattr(socket, 'AF_UNIX') and family == socket.AF_UNIX: with tempfile.NamedTemporaryFile() as tmp: addr = tmp.name else: From 80a5ee00efac4c78c3f161ac22366f07c932265c Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Wed, 23 Nov 2016 17:45:55 -0500 Subject: [PATCH 11/13] win/tests: Fix a couple of loop.create_connection tests --- tests/test_tcp.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/test_tcp.py b/tests/test_tcp.py index a71b8f71..e64a5f4f 100644 --- a/tests/test_tcp.py +++ b/tests/test_tcp.py @@ -219,10 +219,10 @@ def test_create_server_4(self): with sock: addr = sock.getsockname() - with self.assertRaisesRegex(OSError, - "error while attempting.*\('127.*: " - "address already in use"): + re = r"(error while attempting.*\('127.*: address already in use)" + re += r"|(error while attempting to bind.*only one usage)" # win + with self.assertRaisesRegex(OSError, re): self.loop.run_until_complete( self.loop.create_server(object, *addr)) @@ -467,7 +467,10 @@ async def client(): loop=self.loop) async def runner(): - with self.assertRaisesRegex(OSError, 'Bad file'): + re = r"(Bad file)" + re += r"|(is not a socket)" # win + + with self.assertRaisesRegex(OSError, re): await client() self.loop.run_until_complete(runner()) From 6d8636cbe83e29d05f1628bf409fe0a5efad01ae Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Wed, 23 Nov 2016 19:32:24 -0500 Subject: [PATCH 12/13] win: Skip tests that are known not to work on windows --- tests/test_pipes.py | 1 + tests/test_process.py | 4 ++++ tests/test_signals.py | 1 + tests/test_unix.py | 2 ++ uvloop/_testbase.py | 7 +++++++ 5 files changed, 15 insertions(+) diff --git a/tests/test_pipes.py b/tests/test_pipes.py index 8bec52b3..9e23d7b2 100644 --- a/tests/test_pipes.py +++ b/tests/test_pipes.py @@ -62,6 +62,7 @@ def connection_lost(self, exc): self.done.set_result(None) +@tb.skip_windows class _BasePipeTest: def test_read_pipe(self): proto = MyReadPipeProto(loop=self.loop) diff --git a/tests/test_process.py b/tests/test_process.py index 4d26ba24..22218966 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -527,6 +527,7 @@ def cancel_make_transport(): test_utils.run_briefly(self.loop) +@tb.skip_windows # XXX tests will have to be fixed later class Test_UV_Process(_TestProcess, tb.UVTestCase): def test_process_streams_redirect(self): @@ -563,14 +564,17 @@ async def test(): self.assertEqual(se.read(), b'err\n') +@tb.skip_windows # Some tests fail under asyncio class Test_AIO_Process(_TestProcess, tb.AIOTestCase): pass +@tb.skip_windows # XXX tests will have to be fixed later class TestAsyncio_UV_Process(_AsyncioTests, tb.UVTestCase): pass +@tb.skip_windows # Some tests fail under asyncio class TestAsyncio_AIO_Process(_AsyncioTests, tb.AIOTestCase): pass diff --git a/tests/test_signals.py b/tests/test_signals.py index b92e74fe..517f4df2 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -9,6 +9,7 @@ DELAY = 0.1 +@tb.skip_windows class _TestSignal: NEW_LOOP = None diff --git a/tests/test_unix.py b/tests/test_unix.py index 10daf6a4..2985fa5e 100644 --- a/tests/test_unix.py +++ b/tests/test_unix.py @@ -9,6 +9,7 @@ from uvloop import _testbase as tb +@tb.skip_windows class _TestUnix: def test_create_unix_server_1(self): CNT = 0 # number of clients that were successful @@ -453,6 +454,7 @@ class Test_AIO_Unix(_TestUnix, tb.AIOTestCase): pass +@tb.skip_windows class _TestSSL(tb.SSLTestCase): ONLYCERT = tb._cert_fullname(__file__, 'ssl_cert.pem') diff --git a/uvloop/_testbase.py b/uvloop/_testbase.py index 87a833ab..a645645e 100644 --- a/uvloop/_testbase.py +++ b/uvloop/_testbase.py @@ -12,6 +12,7 @@ import select import socket import ssl +import sys import tempfile import threading import time @@ -19,6 +20,12 @@ import uvloop +def skip_windows(o): + dec = unittest.skipIf(sys.platform in ('win32', 'cygwin', 'cli'), + 'skipped on Windows') + return dec(o) + + class MockPattern(str): def __eq__(self, other): return bool(re.search(str(self), other, re.S)) From 5bc48b3dfea9312debe39f8b203bc497349ab373 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Wed, 23 Nov 2016 19:34:08 -0500 Subject: [PATCH 13/13] win/tests: Use IOCP asyncio loop on Windows --- uvloop/_testbase.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/uvloop/_testbase.py b/uvloop/_testbase.py index a645645e..4d6f1877 100644 --- a/uvloop/_testbase.py +++ b/uvloop/_testbase.py @@ -306,7 +306,11 @@ def tearDown(self): super().tearDown() def new_loop(self): - return asyncio.new_event_loop() + if hasattr(asyncio, 'ProactorEventLoop'): + # On Windows try to use IOCP event loop. + return asyncio.ProactorEventLoop() + else: + return asyncio.new_event_loop() def has_IPv6():