Skip to content

Commit

Permalink
Fix Windows subprocess handle issue
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbrochart committed Mar 16, 2020
1 parent 104b9f1 commit b471f27
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 12 deletions.
25 changes: 25 additions & 0 deletions jupyter_server/utils.py
Expand Up @@ -395,3 +395,28 @@ async def _():
return obj

return _()


def _init_asyncio_patch():
if sys.platform.startswith("win"):
# Windows specific event-loop policy. Although WindowsSelectorEventLoop is the current
# default event loop prior to Python 3.8, WindowsProactorEventLoop becomes the default
# in Python 3.8. However, using WindowsProactorEventLoop fails during creation of
# IOLoopKernelClient because it doesn't implement add_reader(), while using
# WindowsSelectorEventLoop fails during asyncio.create_subprocess_exec() because it
# doesn't implement _make_subprocess_transport(). As a result, we need to force the use of
# the WindowsSelectorEventLoop.
# See https://github.com/takluyver/jupyter_kernel_mgmt/issues/31
# The following approach to this is from https://github.com/jupyter/notebook/pull/5047 by @minrk
try:
from asyncio import (
WindowsProactorEventLoopPolicy,
WindowsSelectorEventLoopPolicy,
)
except ImportError:
pass
else:
if type(asyncio.get_event_loop_policy()) is WindowsProactorEventLoopPolicy:
# WindowsProactorEventLoopPolicy is not compatible with tornado 6
# fallback to the pre-3.8 default of Selector
asyncio.set_event_loop_policy(WindowsSelectorEventLoopPolicy())
30 changes: 18 additions & 12 deletions tests/services/sessions/test_api.py
Expand Up @@ -7,12 +7,18 @@

from nbformat.v4 import new_notebook
from nbformat import writes
from jupyter_server.utils import _init_asyncio_patch

from ...utils import expected_http_error

j = lambda r: json.loads(r.body.decode())


@pytest.fixture
def asyncio_patch():
_init_asyncio_patch()


class SessionClient:

def __init__(self, fetch_callable):
Expand Down Expand Up @@ -116,7 +122,7 @@ def session_client(root_dir, fetch):
shutil.rmtree(str(subdir), ignore_errors=True)


async def test_create(session_client):
async def test_create(session_client, asyncio_patch):
# Make sure no sessions exist.
resp = await session_client.list()
sessions = j(resp)
Expand Down Expand Up @@ -146,7 +152,7 @@ async def test_create(session_client):
await session_client.cleanup()


async def test_create_file_session(session_client):
async def test_create_file_session(session_client, asyncio_patch):
resp = await session_client.create('foo/nb1.py', type='file')
assert resp.code == 201
newsession = j(resp)
Expand All @@ -155,7 +161,7 @@ async def test_create_file_session(session_client):
await session_client.cleanup()


async def test_create_console_session(session_client):
async def test_create_console_session(session_client, asyncio_patch):
resp = await session_client.create('foo/abc123', type='console')
assert resp.code == 201
newsession = j(resp)
Expand All @@ -165,7 +171,7 @@ async def test_create_console_session(session_client):
await session_client.cleanup()


async def test_create_deprecated(session_client):
async def test_create_deprecated(session_client, asyncio_patch):
resp = await session_client.create_deprecated('foo/nb1.ipynb')
assert resp.code == 201
newsession = j(resp)
Expand All @@ -176,7 +182,7 @@ async def test_create_deprecated(session_client):
await session_client.cleanup()


async def test_create_with_kernel_id(session_client, fetch):
async def test_create_with_kernel_id(session_client, fetch, asyncio_patch):
# create a new kernel
resp = await fetch('api/kernels', method='POST', allow_nonstandard_methods=True)
kernel = j(resp)
Expand All @@ -201,7 +207,7 @@ async def test_create_with_kernel_id(session_client, fetch):
# Need to find a better solution to this.
await session_client.cleanup()

async def test_delete(session_client):
async def test_delete(session_client, asyncio_patch):
resp = await session_client.create('foo/nb1.ipynb')
newsession = j(resp)
sid = newsession['id']
Expand All @@ -219,7 +225,7 @@ async def test_delete(session_client):
# Need to find a better solution to this.
await session_client.cleanup()

async def test_modify_path(session_client):
async def test_modify_path(session_client, asyncio_patch):
resp = await session_client.create('foo/nb1.ipynb')
newsession = j(resp)
sid = newsession['id']
Expand All @@ -231,7 +237,7 @@ async def test_modify_path(session_client):
# Need to find a better solution to this.
await session_client.cleanup()

async def test_modify_path_deprecated(session_client):
async def test_modify_path_deprecated(session_client, asyncio_patch):
resp = await session_client.create('foo/nb1.ipynb')
newsession = j(resp)
sid = newsession['id']
Expand All @@ -243,7 +249,7 @@ async def test_modify_path_deprecated(session_client):
# Need to find a better solution to this.
await session_client.cleanup()

async def test_modify_type(session_client):
async def test_modify_type(session_client, asyncio_patch):
resp = await session_client.create('foo/nb1.ipynb')
newsession = j(resp)
sid = newsession['id']
Expand All @@ -255,7 +261,7 @@ async def test_modify_type(session_client):
# Need to find a better solution to this.
await session_client.cleanup()

async def test_modify_kernel_name(session_client, fetch):
async def test_modify_kernel_name(session_client, fetch, asyncio_patch):
resp = await session_client.create('foo/nb1.ipynb')
before = j(resp)
sid = before['id']
Expand All @@ -277,7 +283,7 @@ async def test_modify_kernel_name(session_client, fetch):
await session_client.cleanup()


async def test_modify_kernel_id(session_client, fetch):
async def test_modify_kernel_id(session_client, fetch, asyncio_patch):
resp = await session_client.create('foo/nb1.ipynb')
before = j(resp)
sid = before['id']
Expand All @@ -304,4 +310,4 @@ async def test_modify_kernel_id(session_client, fetch):
assert kernel_list == [kernel]

# Need to find a better solution to this.
await session_client.cleanup()
await session_client.cleanup()

0 comments on commit b471f27

Please sign in to comment.