Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ jobs:
- "3.13"
- "3.14"
- "3.14t"
os: [ubuntu-latest, macos-latest]
# TODO: (Vizonex) windows-11-arm
os: [ubuntu-latest, macos-latest, windows-latest]

env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ test = [
'mypy>=0.800',
]
dev = [
'packaging',
'setuptools>=60',
'Cython~=3.0',
]
Expand Down
103 changes: 79 additions & 24 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
if vi < (3, 8):
raise RuntimeError('uvloop requires Python 3.8 or greater')

if sys.platform in ('win32', 'cygwin', 'cli'):
raise RuntimeError('uvloop does not support Windows at the moment')
# TODO: Remove Completely because Winloop Author is mergeing his project to uvloop.
# if sys.platform in ('win32', 'cygwin', 'cli'):
# raise RuntimeError('uvloop does not support Windows at the moment')

import os
import os.path
Expand All @@ -28,6 +29,9 @@
LIBUV_DIR = str(_ROOT / 'vendor' / 'libuv')
LIBUV_BUILD_DIR = str(_ROOT / 'build' / 'libuv-{}'.format(MACHINE))

# NOTE: Mingw was added by another contributor in the winloop project.
MINGW = bool(os.environ.get("MINGW_PREFIX", ""))


def _libuv_build_env():
env = os.environ.copy()
Expand Down Expand Up @@ -83,7 +87,9 @@ class uvloop_build_ext(build_ext):

def initialize_options(self):
super().initialize_options()
self.use_system_libuv = False
# Use mingw if prefix was given for it otherwise it
# will always be false.
self.use_system_libuv = MINGW
self.cython_always = False
self.cython_annotate = None
self.cython_directives = None
Expand All @@ -108,7 +114,8 @@ def finalize_options(self):
need_cythonize = True

if need_cythonize:
import pkg_resources
from packaging.requirements import Requirement
from packaging.version import Version

# Double check Cython presence in case setup_requires
# didn't go into effect (most likely because someone
Expand All @@ -118,17 +125,21 @@ def finalize_options(self):
import Cython
except ImportError:
raise RuntimeError(
'please install {} to compile uvloop from source'.format(
CYTHON_DEPENDENCY))
"please install {} to compile uvloop from source".format(
CYTHON_DEPENDENCY
)
)

cython_dep = pkg_resources.Requirement.parse(CYTHON_DEPENDENCY)
if Cython.__version__ not in cython_dep:
cython_dep = Requirement(CYTHON_DEPENDENCY)
if not cython_dep.specifier.contains(Version(Cython.__version__)):
raise RuntimeError(
'uvloop requires {}, got Cython=={}'.format(
"uvloop requires {}, got Cython=={}".format(
CYTHON_DEPENDENCY, Cython.__version__
))
)
)

from Cython.Build import cythonize


directives = {}
if self.cython_directives:
Expand Down Expand Up @@ -190,6 +201,15 @@ def build_libuv(self):
cwd=LIBUV_BUILD_DIR, env=env, check=True)

def build_extensions(self):
if sys.platform == "win32" and not MINGW:
path = pathlib.Path("vendor", "libuv", "src")
c_files = [p.as_posix() for p in path.iterdir() if p.suffix == ".c"]
c_files += [
p.as_posix() for p in (path / "win").iterdir() if p.suffix == ".c"
]
self.extensions[-1].sources += c_files
super().build_extensions()
return
if self.use_system_libuv:
self.compiler.add_library('uv')

Expand Down Expand Up @@ -229,28 +249,63 @@ def build_extensions(self):
raise RuntimeError(
'unable to read the version from uvloop/_version.py')

if sys.platform == "win32":
from Cython.Build import cythonize
from Cython.Compiler.Main import default_options

default_options["compile_time_env"] = dict(DEFAULT_FREELIST_SIZE=250)
ext = cythonize(
[
Extension(
"uvloop.loop",
sources=["uvloop/loop.pyx"],
include_dirs=[]
if MINGW
else [
"vendor/libuv/src",
"vendor/libuv/src/win",
"vendor/libuv/include",
],
extra_compile_args=["/std:c11", "/experimental:c11atomics"],
# subset of libuv Windows libraries:
extra_link_args=[
(f"-l{lib}" if MINGW else f"{lib}.lib")
for lib in (
"Shell32",
"Ws2_32",
"Advapi32",
"iphlpapi",
"Userenv",
"User32",
"Dbghelp",
"Ole32",
)
],
define_macros=[("WIN32_LEAN_AND_MEAN", 1), ("_WIN32_WINNT", "0x0602")],
),
]
)
else:
ext = [
Extension(
"uvloop.loop",
sources=[
"uvloop/loop.pyx",
],
extra_compile_args=MODULES_CFLAGS,
),
]

setup_requires = []

if not (_ROOT / 'uvloop' / 'loop.c').exists() or '--cython-always' in sys.argv:
if not (_ROOT / "uvloop" / "loop.c").exists() or "--cython-always" in sys.argv:
# No Cython output, require Cython to build.
setup_requires.append(CYTHON_DEPENDENCY)


setup(
version=VERSION,
cmdclass={
'sdist': uvloop_sdist,
'build_ext': uvloop_build_ext
},
ext_modules=[
Extension(
"uvloop.loop",
sources=[
"uvloop/loop.pyx",
],
extra_compile_args=MODULES_CFLAGS
),
],
cmdclass={"sdist": uvloop_sdist, "build_ext": uvloop_build_ext},
ext_modules=ext,
setup_requires=setup_requires,
)
14 changes: 9 additions & 5 deletions tests/test_base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import asyncio
import fcntl
import logging
import os
import random
Expand All @@ -11,6 +10,10 @@
import unittest
import weakref


if sys.platform != "win32":
import fcntl

from unittest import mock
from uvloop._testbase import UVTestCase, AIOTestCase

Expand Down Expand Up @@ -833,10 +836,11 @@ def test_loop_call_later_handle_cancelled(self):
self.assertFalse(handle.cancelled())

def test_loop_std_files_cloexec(self):
# See https://github.com/MagicStack/uvloop/issues/40 for details.
for fd in {0, 1, 2}:
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
self.assertFalse(flags & fcntl.FD_CLOEXEC)
if sys.platform != "win32":
# See https://github.com/MagicStack/uvloop/issues/40 for details.
for fd in {0, 1, 2}:
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
self.assertFalse(flags & fcntl.FD_CLOEXEC)

def test_default_exc_handler_broken(self):
logger = logging.getLogger('asyncio')
Expand Down
Loading
Loading