Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provide a fix for asyncio on Windows + Python pre-3.8 #105

Merged
merged 15 commits into from
Nov 16, 2020
Merged
7 changes: 6 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
python-version: [3.6, 3.7, 3.8]
python-version: [3.6, 3.7, 3.8, 3.9]
os:
- ubuntu-latest
- macos-latest
- windows-latest
exclude:
- os: windows-latest
python-version: 3.9
- os: macos-latest
python-version: 3.9
fail-fast: false

steps:
Expand Down
16 changes: 12 additions & 4 deletions examples/blender/blender.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
import pathlib
import sys

from yapapi import Executor, Task, __version__ as yapapi_version, WorkContext
from yapapi import (
Executor,
Task,
__version__ as yapapi_version,
WorkContext,
windows_event_loop_fix,
)
from yapapi.log import enable_default_logger, log_summary, log_event_repr # noqa
from yapapi.package import vm
from datetime import timedelta
Expand Down Expand Up @@ -86,19 +92,21 @@ async def worker(ctx: WorkContext, tasks):
args = parser.parse_args()

# This is only required when running on Windows with Python prior to 3.8:
utils.windows_event_loop_fix()
windows_event_loop_fix()

enable_default_logger(log_file=args.log_file)

loop = asyncio.get_event_loop()

subnet = args.subnet_tag
sys.stderr.write(
f"yapapi version: {utils.TEXT_COLOR_YELLOW}{yapapi_version}{utils.TEXT_COLOR_DEFAULT}\n"
)
sys.stderr.write(f"Using subnet: {utils.TEXT_COLOR_YELLOW}{subnet}{utils.TEXT_COLOR_DEFAULT}\n")
task = loop.create_task(main(subnet_tag=args.subnet_tag))
try:
asyncio.get_event_loop().run_until_complete(task)
loop.run_until_complete(task)
except (Exception, KeyboardInterrupt) as e:
print(e)
task.cancel()
asyncio.get_event_loop().run_until_complete(task)
loop.run_until_complete(task)
12 changes: 0 additions & 12 deletions examples/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,3 @@ def build_parser(description: str):
"--log-file", default=None, help="Log file for YAPAPI; default: %(default)s"
)
return parser


def windows_event_loop_fix():
"""Set up asyncio to use ProactorEventLoop implementation for new event loops on Windows."""

# For Python 3.8 ProactorEventLoop is already the default on Windows
if sys.platform == "win32" and sys.version_info < (3, 8):

class _WindowsEventPolicy(asyncio.events.BaseDefaultEventLoopPolicy):
_loop_factory = asyncio.windows_events.ProactorEventLoop

asyncio.set_event_loop_policy(_WindowsEventPolicy())
4 changes: 2 additions & 2 deletions examples/yacat/yacat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import pathlib
import sys

from yapapi import Executor, Task, WorkContext
from yapapi import Executor, Task, WorkContext, windows_event_loop_fix
from yapapi.log import enable_default_logger, log_summary, log_event_repr # noqa
from yapapi.package import vm

Expand Down Expand Up @@ -142,7 +142,7 @@ async def worker_find_password(ctx: WorkContext, tasks):
args = parser.parse_args()

# This is only required when running on Windows with Python prior to 3.8:
utils.windows_event_loop_fix()
windows_event_loop_fix()

enable_default_logger(log_file=args.log_file)

Expand Down
12 changes: 12 additions & 0 deletions tests/test_yapapi.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
import toml
from pathlib import Path

Expand All @@ -9,3 +10,14 @@ def test_version():
pyproject = toml.loads(f.read())

assert yapapi.__version__ == pyproject["tool"]["poetry"]["version"]


def test_windows_event_loop_fix():
async def _asyncio_test():
await asyncio.create_subprocess_shell("")

yapapi.windows_event_loop_fix()

l = asyncio.get_event_loop()
t = l.create_task(_asyncio_test())
l.run_until_complete(t)
18 changes: 18 additions & 0 deletions yapapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
"""Golem Python API."""
import asyncio
import sys
import toml

from pathlib import Path
Expand All @@ -21,6 +23,22 @@ def get_version() -> str:
return get_distribution("yapapi").version


def windows_event_loop_fix():
"""
Set up asyncio to use ProactorEventLoop implementation for new event loops on Windows.

This work-around is only needed for Python 3.6 and 3.7.
With Python 3.8, `ProactorEventLoop` is already the default on Windows.
"""

if sys.platform == "win32" and sys.version_info < (3, 8):

class _WindowsEventPolicy(asyncio.events.BaseDefaultEventLoopPolicy):
_loop_factory = asyncio.windows_events.ProactorEventLoop

asyncio.set_event_loop_policy(_WindowsEventPolicy())


__version__: str = get_version()
__all__ = [
"Executor",
Expand Down