Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
35b0fab
start unifying uvloop & winloop together
Vizonex Mar 17, 2026
6827264
Accomplishment: Uvloop now compiles on Windows
Vizonex Mar 18, 2026
0bb1a68
cleanup errors.pyx comments
Vizonex Mar 18, 2026
77bc6dc
forgot about setup.py let's add it
Vizonex Mar 18, 2026
acd5a8b
siginterrupt is not avalible on windows so make it optional
Vizonex Mar 18, 2026
994560c
try placing __forking variables outside of system OS check
Vizonex Mar 18, 2026
d3c2b4a
windows doesn't have childwatchers so disable it
Vizonex Mar 18, 2026
898b310
add gil technqiue for windows to simulate forking
Vizonex Mar 18, 2026
114ae18
add a non-deprecated packaging tool
Vizonex Mar 18, 2026
4037ba8
start introducing windows to the testsuite
Vizonex Mar 18, 2026
7fb3f43
skip fork test in signals if windows
Vizonex Mar 18, 2026
2ed0e62
merge more things from winloop on over to uvloop in test_signals
Vizonex Mar 18, 2026
46bc155
just port all the code over
Vizonex Mar 18, 2026
3d1fc4d
merge more tests
Vizonex Mar 18, 2026
921370b
merge both winloop & uvloop's error handling ways together
Vizonex Mar 18, 2026
250a656
merge more tests
Vizonex Mar 18, 2026
a42c101
merge more of winloop into uvloop, add comment about streams returnin…
Vizonex Mar 18, 2026
aca987b
force trigger workflow temporarly
Vizonex Mar 18, 2026
d8eac6a
Make All versions up to 3.12 work successfully. (#1) (Excluding Windo…
Vizonex Mar 19, 2026
9bd6dd6
temporary fix for working with windows in debug mode
Vizonex Mar 20, 2026
37e54a2
Merge branch 'windows' of https://github.com/Vizonex/uvloop into windows
Vizonex Mar 20, 2026
297be3e
All versions now work excluding debugs for windows in 3.13, 3.14 & 3.14t
Vizonex Mar 20, 2026
3778759
Add __Pyx_MonitoringEventTypes_CyGen_count macro (#3)
Vizonex Mar 21, 2026
2ccaf83
Fix subprocess_shell code (Windows Side) (#4)
Vizonex Mar 21, 2026
0a35c9f
Moved rest of the missing items back to stdlib.pxi (#6)
Vizonex Mar 22, 2026
d3c79f2
update with suggestions made
Vizonex Mar 24, 2026
47ba5e1
swap test_write_buffer_full to skip via wrapper and reenable testing …
Vizonex Apr 6, 2026
d90e020
fix test_pipes.py format
Vizonex Apr 6, 2026
7a2ddc5
Merge branch 'master' into windows
Vizonex Jun 5, 2026
6388dc6
reformat tests
Vizonex Jun 5, 2026
55ed79c
skip test_create_sock_cancel_fd_leak for now... (#8)
Vizonex Jun 5, 2026
1a9f29e
Add Windows debug Makefile workaround. (#9)
Vizonex Jun 27, 2026
a0663f6
CX freeze bugfix windows (#11)
Vizonex Jul 1, 2026
67df390
Tcp Test Fix (#12)
Vizonex Jul 3, 2026
a4c2eff
Merge branch 'master' into windows
Vizonex Jul 14, 2026
3dbf3bf
Implement ssss141414's fixes (#14)
Vizonex Sep 4, 2026
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
73 changes: 72 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,79 @@ jobs:
name: dist-wheels-${{ matrix.os }}-${{ matrix.python }}-${{ matrix.cibw_arch }}
path: wheelhouse/*.whl

build-windows-wheels:
needs: validate-release-request
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
arch: AMD64
build: "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-* cp314-* cp314t-*"
constraint: ""
- os: windows-11-arm
arch: ARM64
build: "cp311-* cp312-* cp313-* cp314-* cp314t-*"
constraint: PIP_CONSTRAINT=${{ github.workspace }}\constraints-windows-arm64.txt

env:
PIP_DISABLE_PIP_VERSION_CHECK: 1

steps:
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with:
fetch-depth: 50
submodules: true

- uses: pypa/cibuildwheel@7c619efba910c04005a835b110b057fc28fd6e93 # v3.2.0
env:
CIBW_BUILD_VERBOSITY: 1
CIBW_BUILD: ${{ matrix.build }}
CIBW_ARCHS: ${{ matrix.arch }}
CIBW_ENVIRONMENT: ${{ matrix.constraint }}

- name: Verify Windows ARM64 wheels
if: matrix.arch == 'ARM64'
shell: pwsh
run: |
Add-Type -AssemblyName System.IO.Compression.FileSystem
Get-ChildItem wheelhouse/*.whl | ForEach-Object {
$archive = [System.IO.Compression.ZipFile]::OpenRead($_.FullName)
try {
$nativeEntry = $archive.Entries |
Where-Object FullName -Like 'uvloop/*.pyd' |
Select-Object -First 1
if (-not $nativeEntry) {
throw "Missing native extension in $($_.Name)"
}

$reader = [System.IO.BinaryReader]::new($nativeEntry.Open())
try {
$bytes = $reader.ReadBytes([int]$nativeEntry.Length)
} finally {
$reader.Dispose()
}
$peOffset = [BitConverter]::ToInt32($bytes, 0x3c)
$machine = [BitConverter]::ToUInt16($bytes, $peOffset + 4)
if ($machine -ne 0xAA64) {
throw ('Expected ARM64 PE machine 0xAA64 in {0}, found 0x{1:X4}' -f $_.Name, $machine)
}
} finally {
$archive.Dispose()
}
}

- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dist-wheels-windows-${{ matrix.arch }}
path: wheelhouse/*.whl

publish:
needs: [build-sdist, build-wheels]
needs:
- build-sdist
- build-wheels
- build-windows-wheels
runs-on: ubuntu-latest

steps:
Expand Down
18 changes: 17 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,18 @@ jobs:
- "3.13"
- "3.14"
- "3.14t"
os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest, macos-latest, windows-latest]
include:
- os: windows-11-arm
python-version: "3.11.9"
- os: windows-11-arm
python-version: "3.12.10"
- os: windows-11-arm
python-version: "3.13.15"
- os: windows-11-arm
python-version: "3.14.7"
- os: windows-11-arm
python-version: "3.14t"

env:
PIP_DISABLE_PIP_VERSION_CHECK: 1
Expand Down Expand Up @@ -57,6 +68,11 @@ jobs:
run: |
brew install gnu-sed libtool autoconf automake

- name: Install Windows ARM64 test prerequisite
if: matrix.os == 'windows-11-arm' && steps.release.outputs.version == 0
run: |
pip install --only-binary cryptography --constraint constraints-windows-arm64.txt cryptography

- name: Install Python Deps
if: steps.release.outputs.version == 0
run: |
Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@

PYTHON ?= python
ROOT = $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
DEBUG_BUILD = --debug
ifeq ($(OS),Windows_NT)
DEBUG_BUILD =
endif


_default: compile


clean:
rm -fr dist/ doc/_build/ *.egg-info uvloop/loop.*.pyd uvloop/loop_d.*.pyd
rm -fr uvloop/*.c uvloop/*.html uvloop/*.so
rm -fr uvloop/*.c uvloop/*.html uvloop/*.so uvloop/*.pyd
rm -fr uvloop/handles/*.html uvloop/includes/*.html
find . -name '__pycache__' | xargs rm -rf

Expand All @@ -35,7 +39,7 @@ compile: clean setup-build


debug: clean
$(PYTHON) setup.py build_ext --inplace --debug \
$(PYTHON) setup.py build_ext --inplace $(DEBUG_BUILD) \
--cython-always \
--cython-annotate \
--cython-directives="linetrace=True" \
Expand Down
1 change: 1 addition & 0 deletions constraints-windows-arm64.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cryptography==46.0.3
19 changes: 19 additions & 0 deletions debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import subprocess
import sys
# Workaround file for Makefile for passing --debug on
# verisons that have a debuggable system as windows does not
# have a debug system like it. And workflows can't seem
# to find where those *_d.lib binaries are...

CMD = ["python", "setup.py", "build_ext", "--inplace", \
"--cython-always",
"--cython-annotate",
"-DUVLOOP_DEBUG","-DCYTHON_TRACE","-DCYTHON_TRACE_NOGIL"]

if sys.platform != "win32":
CMD.append("--debug", "--cython-directives=\"linetrace=True\"")

if __name__ == "__main__":
# Execute and wait for it to finish
sys.exit(subprocess.check_call(CMD, shell=sys.platform == "win32"))
pass
55 changes: 41 additions & 14 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
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')

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


def _libuv_build_env():
env = os.environ.copy()

Expand Down Expand Up @@ -191,6 +187,15 @@ def build_libuv(self):
cwd=LIBUV_BUILD_DIR, env=env, check=True)

def build_extensions(self):
if sys.platform == "win32":
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 @@ -230,28 +235,50 @@ def build_extensions(self):
raise RuntimeError(
'unable to read the version from uvloop/_version.py')

if sys.platform == 'win32':
ext = [
Extension(
'uvloop.loop',
sources=['uvloop/loop.pyx'],
include_dirs=[
'vendor/libuv/src',
'vendor/libuv/src/win',
'vendor/libuv/include',
],
libraries=[
'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:
# 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
),
],
ext_modules=ext,
setup_requires=setup_requires,
)
23 changes: 17 additions & 6 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,9 @@
import unittest
import weakref

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

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

Expand Down Expand Up @@ -125,6 +127,7 @@ def cb():
with self.subTest(debug=debug, meth_name=meth_name):
run_test(debug, meth, stack_adj)

@unittest.skipIf(sys.platform == 'win32', 'asyncio rounding errors')
def test_now_update(self):
async def run():
st = self.loop.time()
Expand Down Expand Up @@ -162,7 +165,13 @@ def cb(inc=10, stop=False):
self.assertFalse(self.loop.is_running())

self.assertLess(finished - started, 0.3)
self.assertGreater(finished - started, 0.04)
if sys.version_info >= (3, 11) and sys.platform == "win32":
# Rounding bug is a thing but gets exteremely
# close to it's target value so some forgiveness
# at the very least is warranted.
self.assertGreater(finished - started, 0.03)
else:
self.assertGreater(finished - started, 0.04)

def test_call_later_2(self):
# Test that loop.call_later triggers an update of
Expand Down Expand Up @@ -207,6 +216,7 @@ def cb(arg):
self.loop.run_forever()
self.assertEqual(calls, ['a'])

@unittest.skipIf(sys.platform == 'win32', 'asyncio rounding errors')
def test_call_later_rounding(self):
# Refs #233, call_later() and call_at() shouldn't call cb early

Expand Down Expand Up @@ -883,10 +893,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