Skip to content

Commit

Permalink
Merge pull request #1255 from gevent/appveyor-37
Browse files Browse the repository at this point in the history
Enable 3.7 on appveyor.
  • Loading branch information
jamadden committed Jul 13, 2018
2 parents 4805d78 + 160dc50 commit 62129a3
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

- Update the bundled libuv from 1.20.1 to 1.22.0.

- Test Python 3.7 on Appveyor. Fix the handling of Popen's
``close_fds`` argument on 3.7.

- Update Python versions tested on Travis, including PyPy to 6.0. See :issue:`1195`.

- :mod:`gevent.queue` imports ``_PySimpleQueue`` instead of
Expand Down
4 changes: 4 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ environment:
# Pre-installed Python versions, which Appveyor may upgrade to
# a later point release.

- PYTHON: "C:\\Python37-x64"
PYTHON_VERSION: "3.7.x"
PYTHON_ARCH: "64"
PYTHON_EXE: python

- PYTHON: "C:\\Python27-x64"
PYTHON_VERSION: "2.7.x" # currently 2.7.13
Expand Down
82 changes: 72 additions & 10 deletions src/gevent/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@
__extra__.remove('STARTUPINFO')
__imports__.append('STARTUPINFO')

if sys.version_info[:2] >= (3, 7):
__imports__.extend([
'ABOVE_NORMAL_PRIORITY_CLASS', 'BELOW_NORMAL_PRIORITY_CLASS',
'HIGH_PRIORITY_CLASS', 'IDLE_PRIORITY_CLASS',
'NORMAL_PRIORITY_CLASS',
'REALTIME_PRIORITY_CLASS',
'CREATE_NO_WINDOW', 'DETACHED_PROCESS',
'CREATE_DEFAULT_ERROR_MODE',
'CREATE_BREAKAWAY_FROM_JOB'
])

actually_imported = copy_globals(__subprocess__, globals(),
only_names=__imports__,
ignore_missing_names=True)
Expand Down Expand Up @@ -462,16 +473,20 @@ def __init__(self, args,
if preexec_fn is not None:
raise ValueError("preexec_fn is not supported on Windows "
"platforms")
any_stdio_set = (stdin is not None or stdout is not None or
stderr is not None)
if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS:
if any_stdio_set:
close_fds = False
else:
if sys.version_info[:2] >= (3, 7):
if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS:
close_fds = True
elif close_fds and any_stdio_set:
raise ValueError("close_fds is not supported on Windows "
"platforms if you redirect stdin/stdout/stderr")
else:
any_stdio_set = (stdin is not None or stdout is not None or
stderr is not None)
if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS:
if any_stdio_set:
close_fds = False
else:
close_fds = True
elif close_fds and any_stdio_set:
raise ValueError("close_fds is not supported on Windows "
"platforms if you redirect stdin/stdout/stderr")
if threadpool is None:
threadpool = hub.threadpool
self.threadpool = threadpool
Expand Down Expand Up @@ -900,6 +915,21 @@ def _find_w9xpopen(self):
"shell or platform.")
return w9xpopen


def _filter_handle_list(self, handle_list):
"""Filter out console handles that can't be used
in lpAttributeList["handle_list"] and make sure the list
isn't empty. This also removes duplicate handles."""
# An handle with it's lowest two bits set might be a special console
# handle that if passed in lpAttributeList["handle_list"], will
# cause it to fail.
# Only works on 3.7+
return list({handle for handle in handle_list
if handle & 0x3 != 0x3
or _winapi.GetFileType(handle) !=
_winapi.FILE_TYPE_CHAR})


def _execute_child(self, args, executable, preexec_fn, close_fds,
pass_fds, cwd, env, universal_newlines,
startupinfo, creationflags, shell,
Expand All @@ -917,12 +947,44 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
# Process startup details
if startupinfo is None:
startupinfo = STARTUPINFO()
if -1 not in (p2cread, c2pwrite, errwrite):
use_std_handles = -1 not in (p2cread, c2pwrite, errwrite)
if use_std_handles:
startupinfo.dwFlags |= STARTF_USESTDHANDLES
startupinfo.hStdInput = p2cread
startupinfo.hStdOutput = c2pwrite
startupinfo.hStdError = errwrite

if hasattr(startupinfo, 'lpAttributeList'):
# Support for Python >= 3.7

attribute_list = startupinfo.lpAttributeList
have_handle_list = bool(attribute_list and
"handle_list" in attribute_list and
attribute_list["handle_list"])

# If we were given an handle_list or need to create one
if have_handle_list or (use_std_handles and close_fds):
if attribute_list is None:
attribute_list = startupinfo.lpAttributeList = {}
handle_list = attribute_list["handle_list"] = \
list(attribute_list.get("handle_list", []))

if use_std_handles:
handle_list += [int(p2cread), int(c2pwrite), int(errwrite)]

handle_list[:] = self._filter_handle_list(handle_list)

if handle_list:
if not close_fds:
import warnings
warnings.warn("startupinfo.lpAttributeList['handle_list'] "
"overriding close_fds", RuntimeWarning)

# When using the handle_list we always request to inherit
# handles but the only handles that will be inherited are
# the ones in the handle_list
close_fds = False

if shell:
startupinfo.dwFlags |= STARTF_USESHOWWINDOW
startupinfo.wShowWindow = SW_HIDE
Expand Down
16 changes: 16 additions & 0 deletions src/greentest/greentest/patched_tests_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,22 @@ def test(*args, **kwargs):
'test_ssl.ThreadedTests.test_check_hostname_idn',
]

if APPVEYOR:
disabled_tests += [
# Raises "AssertionError: wait_threads() failed to cleanup
# 1 threads after 60.0 seconds (count: 3, old count: 2)". reason is
# unknown.
'test_socket.BasicTCPTest.testRecvFrom',
# Ditto.
'test_socket.BasicTCPTest.testRecv',
'test_socket.BasicTCPTest2.testDetach',
'test_socket.BasicTCPTest2.testFromFd',
'test_socket.BasicTCPTest2.testOverFlowRecvFrom',
'test_socket.BasicTCPTest2.testDup',
'test_socket.BasicTCPTest2.testSendAll',
'test_socket.NetworkConnectionAttributesTest.testTimeoutDefault',
]

# if 'signalfd' in os.environ.get('GEVENT_BACKEND', ''):
# # tests that don't interact well with signalfd
# disabled_tests.extend([
Expand Down

0 comments on commit 62129a3

Please sign in to comment.