From 0d514b5efff0f3e124eca269caace6268d6e890a Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Wed, 15 Jun 2022 10:51:21 -0500 Subject: [PATCH 01/15] first set of changes --- .gitignore | 39 ++-------------------- fs_test.py | 23 +++++++++++++ tests/test_fs_event.py | 53 ++++++++++++++++++++++++++++++ uvloop/const.py | 2 ++ uvloop/handles/fsevent.pxd | 14 ++++++++ uvloop/handles/fsevent.pyx | 67 ++++++++++++++++++++++++++++++++++++++ uvloop/includes/uv.pxd | 20 ++++++++++++ uvloop/loop.pxd | 2 ++ uvloop/loop.pyi | 1 + uvloop/loop.pyx | 16 +++++++++ 10 files changed, 201 insertions(+), 36 deletions(-) create mode 100644 fs_test.py create mode 100644 tests/test_fs_event.py create mode 100644 uvloop/const.py create mode 100644 uvloop/handles/fsevent.pxd create mode 100644 uvloop/handles/fsevent.pyx diff --git a/.gitignore b/.gitignore index 3dad090c..e86113d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,3 @@ -*._* -*.pyc -*.pyo -*.ymlc -*.ymlc~ -*.scssc -*.so -*~ -.#* -.DS_Store -.project -.pydevproject -.settings -.idea -/.ropeproject -\#*# -/pub -/test*.py -/.local -/perf.data* -/config_local.yml -/build -__pycache__/ -.d8_history -/*.egg -/*.egg-info -/dist -/.cache -docs/_build -uvloop/loop.*.pyd -/.pytest_cache/ -/.mypy_cache/ -/.vscode -/.eggs -/.venv* -/wheelhouse +uvloop-dev +build +.eggs diff --git a/fs_test.py b/fs_test.py new file mode 100644 index 00000000..15c2fba2 --- /dev/null +++ b/fs_test.py @@ -0,0 +1,23 @@ +import uvloop, uvloop.const +uvloop.install() +import asyncio + +print(f'{uvloop.const.FS_EVENT_CHANGE}') + +def shutdown(): + asyncio.get_running_loop().stop() + +event_count = 0 + +def cb(pth, events): + global h, event_count + print(f'{pth} {events}') + event_count += 1 + if event_count == 4: + h.stop() + asyncio.get_running_loop().call_later(4, shutdown) + +loop = asyncio.get_event_loop() +h = loop.monitor_fs('/tmp/f.txt', cb, 0) + +loop.run_forever() diff --git a/tests/test_fs_event.py b/tests/test_fs_event.py new file mode 100644 index 00000000..4e2eca79 --- /dev/null +++ b/tests/test_fs_event.py @@ -0,0 +1,53 @@ +import asyncio +import socket +import tempfile +import unittest + +from uvloop import _testbase as tb +from uvloop.const import FS_EVENT_CHANGE, FS_EVENT_RENAME + +class Test_UV_FS_EVENT(tb.UVTestCase): + async def _file_writer(self): + f = await self.q.get() + while True: + f.write('hello uvloop\n') + x = await self.q.get() + if x is None: + return + + def fs_event_setup(self): + self.change_event_count = 0 + self.fname = '' + self.q = asyncio.Queue() + + def event_cb(self, ev_fname: bytes, evt: int) : + self.assertEqual(ev_fname, self.fname) + self.assertEqual(evt, FS_EVENT_CHANGE) + self.change_event_count += 1 + if self.change_event_count < 4: + self.q.put_nowait(0) + else: + self.q.put_nowait(None) + + def test_fs_event_change(self): + self.fs_event_setup() + + async def run(write_task): + self.q.put_nowait(tf) + self.q.put_nowait(0) + try: + await asyncio.wait_for(write_task, 4) + except asyncio.TimeoutError: + write_task.cancel() + self.loop.stop() + + with tempfile.NamedTemporaryFile('wt') as tf: + self.fname = tf.name.encode() + h = self.loop.monitor_fs(tf.name, self.event_cb, 0) + try : + self.loop.run_until_complete(run(self.loop.create_task(self._file_writer()))) + h.stop() + finally : + self.loop.close() + + self.assertEqual(self.change_event_count, 4) diff --git a/uvloop/const.py b/uvloop/const.py new file mode 100644 index 00000000..034da841 --- /dev/null +++ b/uvloop/const.py @@ -0,0 +1,2 @@ +FS_EVENT_CHANGE = 2 +FS_EVENT_RENAME = 1 diff --git a/uvloop/handles/fsevent.pxd b/uvloop/handles/fsevent.pxd new file mode 100644 index 00000000..a3508dc7 --- /dev/null +++ b/uvloop/handles/fsevent.pxd @@ -0,0 +1,14 @@ +cdef class UVFSEvent(UVHandle): + cdef: + object callback + + cdef _init(self, Loop loop, char* path, object callback, + int flags) + + cdef _stop(self) + #cdef start(self) + #cdef get_when(self) + + @staticmethod + cdef UVFSEvent new(Loop loop, char* path, object callback, + int flags) diff --git a/uvloop/handles/fsevent.pyx b/uvloop/handles/fsevent.pyx new file mode 100644 index 00000000..0afe6aa0 --- /dev/null +++ b/uvloop/handles/fsevent.pyx @@ -0,0 +1,67 @@ +@cython.no_gc_clear +cdef class UVFSEvent(UVHandle): + cdef _init(self, Loop loop, char* path, object callback, + int flags): + + cdef int err + + self._start_init(loop) + + self._handle = PyMem_RawMalloc(sizeof(uv.uv_fs_event_t)) + if self._handle is NULL: + self._abort_init() + raise MemoryError() + + err = uv.uv_fs_event_init(self._loop.uvloop, self._handle) + if err < 0: + self._abort_init() + raise convert_error(err) + + self._finish_init() + + self.callback = callback + + err = uv.uv_fs_event_start(self._handle, __uvfsevent_callback, path, flags) + if err < 0: + self._abort_init() + raise convert_error(err) + + + cdef _stop(self): + cdef int err + + if not self._is_alive(): + return + + err = uv.uv_fs_event_stop(self._handle) + self.closed = True + if err < 0: + exc = convert_error(err) + self._fatal_error(exc, True) + return + + def stop(self): + self._stop() + + @staticmethod + cdef UVFSEvent new(Loop loop, char* path, object callback, + int flags): + + cdef UVFSEvent handle + handle = UVFSEvent.__new__(UVFSEvent) + handle._init(loop, path, callback, flags) + return handle + + +cdef void __uvfsevent_callback(uv.uv_fs_event_t* handle, const char *filename, + int events, int status) with gil: + if __ensure_handle_data(handle, "UVFSEvent callback") == 0: + return + + cdef: + UVFSEvent fs_event = handle.data + + try: + fs_event.callback(filename, events) + except BaseException as ex: + fs_event._error(ex, False) diff --git a/uvloop/includes/uv.pxd b/uvloop/includes/uv.pxd index 0b0f1da9..c0030c40 100644 --- a/uvloop/includes/uv.pxd +++ b/uvloop/includes/uv.pxd @@ -183,6 +183,10 @@ cdef extern from "uv.h" nogil: int pid # ... + ctypedef struct uv_fs_event_t: + void* data + # ... + ctypedef enum uv_req_type: UV_UNKNOWN_REQ = 0, UV_REQ, @@ -215,6 +219,15 @@ cdef extern from "uv.h" nogil: UV_LEAVE_GROUP = 0, UV_JOIN_GROUP + ctypedef enum uv_fs_event: + UV_RENAME = 1, + UV_CHANGE = 2 + + ctypedef enum uv_fs_event_flags: + UV_FS_EVENT_WATCH_ENTRY = 1, + UV_FS_EVENT_STAT = 2, + UV_FS_EVENT_RECURSIVE = 4 + const char* uv_strerror(int err) const char* uv_err_name(int err) @@ -253,6 +266,7 @@ cdef extern from "uv.h" nogil: const uv_buf_t* buf, const system.sockaddr* addr, unsigned flags) with gil + ctypedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char *filename, int events, int status) with gil # Generic request functions int uv_cancel(uv_req_t* req) @@ -397,6 +411,12 @@ cdef extern from "uv.h" nogil: int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) int uv_poll_stop(uv_poll_t* poll) + # FS Event + + int uv_fs_event_init(uv_loop_t *loop, uv_fs_event_t *handle) + int uv_fs_event_start(uv_fs_event_t *handle, uv_fs_event_cb cb, const char *path, unsigned int flags) + int uv_fs_event_stop(uv_fs_event_t *handle) + # Misc ctypedef struct uv_timeval_t: diff --git a/uvloop/loop.pxd b/uvloop/loop.pxd index 06bee851..b390e5ca 100644 --- a/uvloop/loop.pxd +++ b/uvloop/loop.pxd @@ -190,6 +190,7 @@ cdef class Loop: cdef _sock_connect(self, sock, address) cdef _sock_connect_cb(self, fut, sock, address) + cdef _monitor_fs(self, char* path, int flags, callback) cdef _sock_set_reuseport(self, int fd) cdef _setup_or_resume_signals(self) @@ -220,6 +221,7 @@ include "handles/streamserver.pxd" include "handles/tcp.pxd" include "handles/pipe.pxd" include "handles/process.pxd" +include "handles/fsevent.pxd" include "request.pxd" include "sslproto.pxd" diff --git a/uvloop/loop.pyi b/uvloop/loop.pyi index 39285fc7..8c05377a 100644 --- a/uvloop/loop.pyi +++ b/uvloop/loop.pyi @@ -287,3 +287,4 @@ class Loop: *, fallback: bool = ... ) -> int: ... + def monitor_fs(self, path: str, callback: Callable[..., Any], flags: int) -> asyncio.Handle: ... diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index d9b5aaac..37c65275 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -3116,6 +3116,19 @@ cdef class Loop: await waiter return udp, protocol + def monitor_fs(self, path: str, callback, flags: int) -> asyncio.Handle: + p_bytes = path.encode('UTF-8') + cdef char* c_str_path = p_bytes + return self._monitor_fs(c_str_path, flags, callback) + + cdef _monitor_fs(self, char* path, int flags, callback): + cdef: + UVFSEvent fsevent + + self._check_closed() + + return UVFSEvent.new(self, path, callback, flags) + def _check_default_executor(self): if self._executor_shutdown_called: raise RuntimeError('Executor shutdown has been called') @@ -3264,6 +3277,7 @@ include "handles/streamserver.pyx" include "handles/tcp.pyx" include "handles/pipe.pyx" include "handles/process.pyx" +include "handles/fsevent.pyx" include "request.pyx" include "dns.pyx" @@ -3273,6 +3287,8 @@ include "handles/udp.pyx" include "server.pyx" +DEF FS_EVENT_CHANGE = 2 +DEF FS_EVENT_RENAME = 1 # Used in UVProcess cdef vint __atfork_installed = 0 From 44b9d3ea68baa767443630decae3400950c6d34d Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Wed, 15 Jun 2022 15:36:48 -0500 Subject: [PATCH 02/15] finished testing functionality of fs_events --- tests/test_fs_event.py | 55 ++++++++++++++++++++++++++++++++---- tests/test_get_uvloop_ptr.py | 6 ++++ uvloop/handles/fsevent.pxd | 2 +- uvloop/handles/fsevent.pyx | 17 ++++++----- uvloop/loop.pxd | 2 +- uvloop/loop.pyx | 3 ++ 6 files changed, 71 insertions(+), 14 deletions(-) create mode 100644 tests/test_get_uvloop_ptr.py diff --git a/tests/test_fs_event.py b/tests/test_fs_event.py index 4e2eca79..61cfbf3b 100644 --- a/tests/test_fs_event.py +++ b/tests/test_fs_event.py @@ -1,16 +1,17 @@ import asyncio -import socket +import os.path import tempfile import unittest from uvloop import _testbase as tb from uvloop.const import FS_EVENT_CHANGE, FS_EVENT_RENAME -class Test_UV_FS_EVENT(tb.UVTestCase): +class Test_UV_FS_EVENT_CHANGE(tb.UVTestCase): async def _file_writer(self): f = await self.q.get() while True: f.write('hello uvloop\n') + f.flush() x = await self.q.get() if x is None: return @@ -21,7 +22,8 @@ def fs_event_setup(self): self.q = asyncio.Queue() def event_cb(self, ev_fname: bytes, evt: int) : - self.assertEqual(ev_fname, self.fname) + _d, fn = os.path.split(self.fname) + self.assertEqual(ev_fname, fn) self.assertEqual(evt, FS_EVENT_CHANGE) self.change_event_count += 1 if self.change_event_count < 4: @@ -34,7 +36,6 @@ def test_fs_event_change(self): async def run(write_task): self.q.put_nowait(tf) - self.q.put_nowait(0) try: await asyncio.wait_for(write_task, 4) except asyncio.TimeoutError: @@ -46,8 +47,52 @@ async def run(write_task): h = self.loop.monitor_fs(tf.name, self.event_cb, 0) try : self.loop.run_until_complete(run(self.loop.create_task(self._file_writer()))) - h.stop() + h.close() finally : self.loop.close() self.assertEqual(self.change_event_count, 4) + +class Test_UV_FS_EVENT_RENAME(tb.UVTestCase): + async def _file_renamer(self): + await self.q.get() + os.rename(os.path.join(self.dname, self.changed_name), os.path.join(self.dname, self.changed_name+"-new")) + await self.q.get() + + def fs_event_setup(self): + self.dname = '' + self.changed_name = "hello_fs_event.txt" + self.changed_set = {self.changed_name, self.changed_name + '-new'} + self.q = asyncio.Queue() + + def event_cb(self, ev_fname: bytes, evt: int) : + ev_fname = ev_fname.decode() + self.assertEqual(evt, FS_EVENT_RENAME) + self.changed_set.remove(ev_fname) + if len(self.changed_set) == 0: + self.q.put_nowait(None) + + def test_fs_event_rename(self): + self.fs_event_setup() + + async def run(write_task): + self.q.put_nowait(0) + try: + await asyncio.wait_for(write_task, 4) + except asyncio.TimeoutError: + write_task.cancel() + self.loop.stop() + + with tempfile.TemporaryDirectory() as td_name: + self.dname = td_name + f = open(os.path.join(td_name, self.changed_name), 'wt') + f.write('hello!') + f.close() + h = self.loop.monitor_fs(td_name, self.event_cb, 0) + try : + self.loop.run_until_complete(run(self.loop.create_task(self._file_renamer()))) + h.close() + finally : + self.loop.close() + + self.assertEqual(len(self.changed_set), 0) diff --git a/tests/test_get_uvloop_ptr.py b/tests/test_get_uvloop_ptr.py new file mode 100644 index 00000000..c62dbc5a --- /dev/null +++ b/tests/test_get_uvloop_ptr.py @@ -0,0 +1,6 @@ +from uvloop import _testbase as tb + +class Test_UV_FS_EVENT_CHANGE(tb.UVTestCase): + def test_fs_event_change(self): + self.assertGreater(self.loop.get_uvloop_ptr(), 0) + diff --git a/uvloop/handles/fsevent.pxd b/uvloop/handles/fsevent.pxd index a3508dc7..0368b72e 100644 --- a/uvloop/handles/fsevent.pxd +++ b/uvloop/handles/fsevent.pxd @@ -5,7 +5,7 @@ cdef class UVFSEvent(UVHandle): cdef _init(self, Loop loop, char* path, object callback, int flags) - cdef _stop(self) + cdef _close(self) #cdef start(self) #cdef get_when(self) diff --git a/uvloop/handles/fsevent.pyx b/uvloop/handles/fsevent.pyx index 0afe6aa0..a835b50a 100644 --- a/uvloop/handles/fsevent.pyx +++ b/uvloop/handles/fsevent.pyx @@ -17,31 +17,34 @@ cdef class UVFSEvent(UVHandle): self._abort_init() raise convert_error(err) - self._finish_init() - - self.callback = callback err = uv.uv_fs_event_start(self._handle, __uvfsevent_callback, path, flags) if err < 0: self._abort_init() raise convert_error(err) + self._finish_init() - cdef _stop(self): + self.callback = callback + + + cdef _close(self): cdef int err if not self._is_alive(): return err = uv.uv_fs_event_stop(self._handle) - self.closed = True if err < 0: exc = convert_error(err) self._fatal_error(exc, True) return - def stop(self): - self._stop() + UVHandle._close(self) + + + def close(self): + self._close() @staticmethod cdef UVFSEvent new(Loop loop, char* path, object callback, diff --git a/uvloop/loop.pxd b/uvloop/loop.pxd index b390e5ca..1401fffa 100644 --- a/uvloop/loop.pxd +++ b/uvloop/loop.pxd @@ -4,7 +4,7 @@ from .includes cimport uv from .includes cimport system -from libc.stdint cimport uint64_t, uint32_t, int64_t +from libc.stdint cimport uint64_t, uint32_t, int64_t, uintptr_t include "includes/consts.pxi" diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index 37c65275..c792e98b 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -3129,6 +3129,9 @@ cdef class Loop: return UVFSEvent.new(self, path, callback, flags) + def get_uvloop_ptr(self) -> int: + return self.uvloop + def _check_default_executor(self): if self._executor_shutdown_called: raise RuntimeError('Executor shutdown has been called') From 93fa1b3a107c29bee3e5f0c1658751bee1561a60 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Wed, 15 Jun 2022 15:50:44 -0500 Subject: [PATCH 03/15] remove file I was using for testing --- fs_test.py | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 fs_test.py diff --git a/fs_test.py b/fs_test.py deleted file mode 100644 index 15c2fba2..00000000 --- a/fs_test.py +++ /dev/null @@ -1,23 +0,0 @@ -import uvloop, uvloop.const -uvloop.install() -import asyncio - -print(f'{uvloop.const.FS_EVENT_CHANGE}') - -def shutdown(): - asyncio.get_running_loop().stop() - -event_count = 0 - -def cb(pth, events): - global h, event_count - print(f'{pth} {events}') - event_count += 1 - if event_count == 4: - h.stop() - asyncio.get_running_loop().call_later(4, shutdown) - -loop = asyncio.get_event_loop() -h = loop.monitor_fs('/tmp/f.txt', cb, 0) - -loop.run_forever() From 9fb994c5e11adf49ca09b53de3d1f0b0c4c1ede0 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Wed, 15 Jun 2022 16:50:30 -0500 Subject: [PATCH 04/15] correct formatting etc --- tests/test_fs_event.py | 24 ++++++++++++++---------- tests/test_get_uvloop_ptr.py | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/tests/test_fs_event.py b/tests/test_fs_event.py index 61cfbf3b..a16fef5b 100644 --- a/tests/test_fs_event.py +++ b/tests/test_fs_event.py @@ -1,11 +1,11 @@ import asyncio import os.path import tempfile -import unittest from uvloop import _testbase as tb from uvloop.const import FS_EVENT_CHANGE, FS_EVENT_RENAME + class Test_UV_FS_EVENT_CHANGE(tb.UVTestCase): async def _file_writer(self): f = await self.q.get() @@ -21,7 +21,7 @@ def fs_event_setup(self): self.fname = '' self.q = asyncio.Queue() - def event_cb(self, ev_fname: bytes, evt: int) : + def event_cb(self, ev_fname: bytes, evt: int): _d, fn = os.path.split(self.fname) self.assertEqual(ev_fname, fn) self.assertEqual(evt, FS_EVENT_CHANGE) @@ -45,18 +45,21 @@ async def run(write_task): with tempfile.NamedTemporaryFile('wt') as tf: self.fname = tf.name.encode() h = self.loop.monitor_fs(tf.name, self.event_cb, 0) - try : - self.loop.run_until_complete(run(self.loop.create_task(self._file_writer()))) + try: + self.loop.run_until_complete(run( + self.loop.create_task(self._file_writer()))) h.close() - finally : + finally: self.loop.close() self.assertEqual(self.change_event_count, 4) + class Test_UV_FS_EVENT_RENAME(tb.UVTestCase): async def _file_renamer(self): await self.q.get() - os.rename(os.path.join(self.dname, self.changed_name), os.path.join(self.dname, self.changed_name+"-new")) + os.rename(os.path.join(self.dname, self.changed_name), + os.path.join(self.dname, self.changed_name + "-new")) await self.q.get() def fs_event_setup(self): @@ -65,7 +68,7 @@ def fs_event_setup(self): self.changed_set = {self.changed_name, self.changed_name + '-new'} self.q = asyncio.Queue() - def event_cb(self, ev_fname: bytes, evt: int) : + def event_cb(self, ev_fname: bytes, evt: int): ev_fname = ev_fname.decode() self.assertEqual(evt, FS_EVENT_RENAME) self.changed_set.remove(ev_fname) @@ -89,10 +92,11 @@ async def run(write_task): f.write('hello!') f.close() h = self.loop.monitor_fs(td_name, self.event_cb, 0) - try : - self.loop.run_until_complete(run(self.loop.create_task(self._file_renamer()))) + try: + self.loop.run_until_complete(run( + self.loop.create_task(self._file_renamer()))) h.close() - finally : + finally: self.loop.close() self.assertEqual(len(self.changed_set), 0) diff --git a/tests/test_get_uvloop_ptr.py b/tests/test_get_uvloop_ptr.py index c62dbc5a..4e03e098 100644 --- a/tests/test_get_uvloop_ptr.py +++ b/tests/test_get_uvloop_ptr.py @@ -1,6 +1,6 @@ from uvloop import _testbase as tb + class Test_UV_FS_EVENT_CHANGE(tb.UVTestCase): def test_fs_event_change(self): self.assertGreater(self.loop.get_uvloop_ptr(), 0) - From 39b2fedc8712ca2d829e959ed7bfde4efdeb47f6 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Tue, 21 Jun 2022 15:04:16 -0500 Subject: [PATCH 05/15] newer Python versions do not have asyncio.events._TransProtPair, define the tuple type directly --- uvloop/loop.pyi | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/uvloop/loop.pyi b/uvloop/loop.pyi index 8c05377a..59513b0f 100644 --- a/uvloop/loop.pyi +++ b/uvloop/loop.pyi @@ -21,6 +21,7 @@ _T = TypeVar('_T') _Context = Dict[str, Any] _ExceptionHandler = Callable[[asyncio.AbstractEventLoop, _Context], Any] _SSLContext = Union[bool, None, ssl.SSLContext] +_TransProtPair = Tuple[asyncio.transports.BaseTransport, asyncio.transports.BaseTransport] class Loop: def call_soon( @@ -155,7 +156,7 @@ class Loop: server_hostname: Optional[str] = ..., ssl_handshake_timeout: Optional[float] = ..., ssl_shutdown_timeout: Optional[float] = ..., - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... @overload async def create_connection( self, @@ -172,7 +173,7 @@ class Loop: server_hostname: Optional[str] = ..., ssl_handshake_timeout: Optional[float] = ..., ssl_shutdown_timeout: Optional[float] = ..., - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... async def create_unix_server( self, protocol_factory: asyncio.events._ProtocolFactory, @@ -195,7 +196,7 @@ class Loop: server_hostname: Optional[str] = ..., ssl_handshake_timeout: Optional[float] = ..., ssl_shutdown_timeout: Optional[float] = ..., - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... def default_exception_handler(self, context: _Context) -> None: ... def get_exception_handler(self) -> Optional[_ExceptionHandler]: ... def set_exception_handler(self, handler: Optional[_ExceptionHandler]) -> None: ... @@ -217,7 +218,7 @@ class Loop: ssl: _SSLContext = ..., ssl_handshake_timeout: Optional[float] = ..., ssl_shutdown_timeout: Optional[float] = ..., - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... async def run_in_executor( self, executor: Any, func: Callable[..., _T], *args: Any ) -> _T: ... @@ -231,7 +232,7 @@ class Loop: stdout: Any = ..., stderr: Any = ..., **kwargs: Any, - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... async def subprocess_exec( self, protocol_factory: asyncio.events._ProtocolFactory, @@ -240,13 +241,13 @@ class Loop: stdout: Any = ..., stderr: Any = ..., **kwargs: Any, - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... async def connect_read_pipe( self, protocol_factory: asyncio.events._ProtocolFactory, pipe: Any - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... async def connect_write_pipe( self, protocol_factory: asyncio.events._ProtocolFactory, pipe: Any - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... def add_signal_handler( self, sig: int, callback: Callable[..., Any], *args: Any ) -> None: ... @@ -264,7 +265,7 @@ class Loop: reuse_port: Optional[bool] = ..., allow_broadcast: Optional[bool] = ..., sock: Optional[socket] = ..., - ) -> asyncio.events._TransProtPair: ... + ) -> _TransProtPair: ... async def shutdown_asyncgens(self) -> None: ... async def shutdown_default_executor(self) -> None: ... # Loop doesn't implement these, but since they are marked as abstract in typeshed, From 950d8be078c0da7efa4e0d02123ba2d5395eed79 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Mon, 18 Jul 2022 12:14:15 -0500 Subject: [PATCH 06/15] various changes per maintainer following review --- tests/test_fs_event.py | 6 +++--- uvloop/const.py | 7 +++++-- uvloop/handles/fsevent.pxd | 2 -- uvloop/loop.pxd | 1 - uvloop/loop.pyx | 14 ++++---------- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/tests/test_fs_event.py b/tests/test_fs_event.py index a16fef5b..124cdf28 100644 --- a/tests/test_fs_event.py +++ b/tests/test_fs_event.py @@ -3,7 +3,7 @@ import tempfile from uvloop import _testbase as tb -from uvloop.const import FS_EVENT_CHANGE, FS_EVENT_RENAME +from uvloop.const import FS_EVENT class Test_UV_FS_EVENT_CHANGE(tb.UVTestCase): @@ -24,7 +24,7 @@ def fs_event_setup(self): def event_cb(self, ev_fname: bytes, evt: int): _d, fn = os.path.split(self.fname) self.assertEqual(ev_fname, fn) - self.assertEqual(evt, FS_EVENT_CHANGE) + self.assertEqual(evt, FS_EVENT.CHANGE) self.change_event_count += 1 if self.change_event_count < 4: self.q.put_nowait(0) @@ -70,7 +70,7 @@ def fs_event_setup(self): def event_cb(self, ev_fname: bytes, evt: int): ev_fname = ev_fname.decode() - self.assertEqual(evt, FS_EVENT_RENAME) + self.assertEqual(evt, FS_EVENT.RENAME) self.changed_set.remove(ev_fname) if len(self.changed_set) == 0: self.q.put_nowait(None) diff --git a/uvloop/const.py b/uvloop/const.py index 034da841..1a87e87c 100644 --- a/uvloop/const.py +++ b/uvloop/const.py @@ -1,2 +1,5 @@ -FS_EVENT_CHANGE = 2 -FS_EVENT_RENAME = 1 +import enum + +class FS_EVENT(enum.IntEnum): + CHANGE = 2 + RENAME = 1 diff --git a/uvloop/handles/fsevent.pxd b/uvloop/handles/fsevent.pxd index 0368b72e..6ccc82bf 100644 --- a/uvloop/handles/fsevent.pxd +++ b/uvloop/handles/fsevent.pxd @@ -6,8 +6,6 @@ cdef class UVFSEvent(UVHandle): int flags) cdef _close(self) - #cdef start(self) - #cdef get_when(self) @staticmethod cdef UVFSEvent new(Loop loop, char* path, object callback, diff --git a/uvloop/loop.pxd b/uvloop/loop.pxd index 1401fffa..78c70380 100644 --- a/uvloop/loop.pxd +++ b/uvloop/loop.pxd @@ -190,7 +190,6 @@ cdef class Loop: cdef _sock_connect(self, sock, address) cdef _sock_connect_cb(self, fut, sock, address) - cdef _monitor_fs(self, char* path, int flags, callback) cdef _sock_set_reuseport(self, int fd) cdef _setup_or_resume_signals(self) diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index c792e98b..d54b86a9 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -3116,18 +3116,12 @@ cdef class Loop: await waiter return udp, protocol - def monitor_fs(self, path: str, callback, flags: int) -> asyncio.Handle: + def monitor_fs(self, path: str, callback, recursive: bool) -> asyncio.Handle: + self._check_closed() p_bytes = path.encode('UTF-8') + flags = 4 if recursive else 0 cdef char* c_str_path = p_bytes - return self._monitor_fs(c_str_path, flags, callback) - - cdef _monitor_fs(self, char* path, int flags, callback): - cdef: - UVFSEvent fsevent - - self._check_closed() - - return UVFSEvent.new(self, path, callback, flags) + return UVFSEvent.new(self, c_str_path, callback, flags) def get_uvloop_ptr(self) -> int: return self.uvloop From 97aabcfdde6ecc51d1a10e70da9f7f567b027ee7 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Mon, 18 Jul 2022 12:23:33 -0500 Subject: [PATCH 07/15] dang, forgot test_sourcecode.py... fixed --- uvloop/const.py | 1 + 1 file changed, 1 insertion(+) diff --git a/uvloop/const.py b/uvloop/const.py index 1a87e87c..82c0a350 100644 --- a/uvloop/const.py +++ b/uvloop/const.py @@ -1,5 +1,6 @@ import enum + class FS_EVENT(enum.IntEnum): CHANGE = 2 RENAME = 1 From de85d80f4ee693e9b8d232a91e32f3b8d6491dc3 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Tue, 19 Jul 2022 12:49:56 -0500 Subject: [PATCH 08/15] recursive param in test should be boolean, not 0 --- tests/test_fs_event.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_fs_event.py b/tests/test_fs_event.py index 124cdf28..46ef152b 100644 --- a/tests/test_fs_event.py +++ b/tests/test_fs_event.py @@ -44,7 +44,7 @@ async def run(write_task): with tempfile.NamedTemporaryFile('wt') as tf: self.fname = tf.name.encode() - h = self.loop.monitor_fs(tf.name, self.event_cb, 0) + h = self.loop.monitor_fs(tf.name, self.event_cb, False) try: self.loop.run_until_complete(run( self.loop.create_task(self._file_writer()))) @@ -91,7 +91,7 @@ async def run(write_task): f = open(os.path.join(td_name, self.changed_name), 'wt') f.write('hello!') f.close() - h = self.loop.monitor_fs(td_name, self.event_cb, 0) + h = self.loop.monitor_fs(td_name, self.event_cb, False) try: self.loop.run_until_complete(run( self.loop.create_task(self._file_renamer()))) From 48f3a26096b1e9f4cbad0ae2d0e19ff39ff28bfa Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Tue, 19 Jul 2022 13:08:11 -0500 Subject: [PATCH 09/15] move function to get underlying loop pointer outside the object, exported as sharedlib c function --- tests/test_get_uvloop_ptr.py | 18 +++++++++++++++--- uvloop/loop.pyx | 6 +++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/test_get_uvloop_ptr.py b/tests/test_get_uvloop_ptr.py index 4e03e098..14a0c87f 100644 --- a/tests/test_get_uvloop_ptr.py +++ b/tests/test_get_uvloop_ptr.py @@ -1,6 +1,18 @@ +import uvloop from uvloop import _testbase as tb +import ctypes +import os.path -class Test_UV_FS_EVENT_CHANGE(tb.UVTestCase): - def test_fs_event_change(self): - self.assertGreater(self.loop.get_uvloop_ptr(), 0) +class TestGetUvLoopPtr(tb.UVTestCase): + def test_get_uv_loop_ptr(self): + so_lib_path = None + dir_p = os.path.split(uvloop.__file__)[0] + for n in os.listdir(dir_p): + if n.endswith('.so'): + so_lib_path = os.path.join(dir_p, n) + if so_lib_path is None: + raise RuntimeError('could not find uvloop shared lib') + cdll = ctypes.CDLL(so_lib_path) + self.assertGreater(cdll.get_uv_loop_ptr(ctypes.py_object(self.loop)), + 0) diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index d54b86a9..9c33ce93 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -3123,9 +3123,6 @@ cdef class Loop: cdef char* c_str_path = p_bytes return UVFSEvent.new(self, c_str_path, callback, flags) - def get_uvloop_ptr(self) -> int: - return self.uvloop - def _check_default_executor(self): if self._executor_shutdown_called: raise RuntimeError('Executor shutdown has been called') @@ -3191,6 +3188,9 @@ cdef class Loop: self.call_soon_threadsafe(future.set_exception, ex) +cdef extern uv.uv_loop_t* get_uv_loop_ptr(PyObject* loop) nogil: + return (loop).uvloop + cdef void __loop_alloc_buffer(uv.uv_handle_t* uvhandle, size_t suggested_size, uv.uv_buf_t* buf) with gil: From 4c20dd9a5cf891fe72b7b745bb86f1ebeacc7a3e Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Tue, 19 Jul 2022 13:16:15 -0500 Subject: [PATCH 10/15] since type is assumed int, can certainly be negative --- tests/test_get_uvloop_ptr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_get_uvloop_ptr.py b/tests/test_get_uvloop_ptr.py index 14a0c87f..612cc3ae 100644 --- a/tests/test_get_uvloop_ptr.py +++ b/tests/test_get_uvloop_ptr.py @@ -14,5 +14,5 @@ def test_get_uv_loop_ptr(self): if so_lib_path is None: raise RuntimeError('could not find uvloop shared lib') cdll = ctypes.CDLL(so_lib_path) - self.assertGreater(cdll.get_uv_loop_ptr(ctypes.py_object(self.loop)), + self.assertNotEqual(cdll.get_uv_loop_ptr(ctypes.py_object(self.loop)), 0) From 55d5ec9328dc1200003498458a4cad421682f388 Mon Sep 17 00:00:00 2001 From: Jens Jorgensen Date: Tue, 19 Jul 2022 16:39:53 -0500 Subject: [PATCH 11/15] fix indentation --- tests/test_get_uvloop_ptr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_get_uvloop_ptr.py b/tests/test_get_uvloop_ptr.py index 612cc3ae..f1bb3cee 100644 --- a/tests/test_get_uvloop_ptr.py +++ b/tests/test_get_uvloop_ptr.py @@ -15,4 +15,4 @@ def test_get_uv_loop_ptr(self): raise RuntimeError('could not find uvloop shared lib') cdll = ctypes.CDLL(so_lib_path) self.assertNotEqual(cdll.get_uv_loop_ptr(ctypes.py_object(self.loop)), - 0) + 0) From 33296bf53afd272262ba824075c728bb3c121c8c Mon Sep 17 00:00:00 2001 From: Fantix King Date: Mon, 5 Sep 2022 12:14:35 -0400 Subject: [PATCH 12/15] Fix fs_event implementation * Move const into fsevent.pyx and import with uvloop.loop * Use libuv const to replace the redeclaration * Hide the _monitor_fs API * Duck-typing the asyncio.Handle API * Dropped recursive flag which is not functional on Linux * Proper UVHandle start and stop for fs_event * Callback with context * Errors in callback won't stop the watch now * Dropped the libuv loop pointer (already implemented in other PR) --- tests/test_fs_event.py | 22 +++++---- tests/test_get_uvloop_ptr.py | 18 ------- uvloop/const.py | 6 --- uvloop/handles/fsevent.pxd | 10 ++-- uvloop/handles/fsevent.pyx | 93 ++++++++++++++++++++++++++---------- uvloop/includes/uv.pxd | 15 +++--- uvloop/loop.pxd | 2 +- uvloop/loop.pyi | 1 - uvloop/loop.pyx | 19 ++++---- 9 files changed, 103 insertions(+), 83 deletions(-) delete mode 100644 tests/test_get_uvloop_ptr.py delete mode 100644 uvloop/const.py diff --git a/tests/test_fs_event.py b/tests/test_fs_event.py index 46ef152b..7284875a 100644 --- a/tests/test_fs_event.py +++ b/tests/test_fs_event.py @@ -3,7 +3,7 @@ import tempfile from uvloop import _testbase as tb -from uvloop.const import FS_EVENT +from uvloop.loop import FileSystemEvent class Test_UV_FS_EVENT_CHANGE(tb.UVTestCase): @@ -21,10 +21,10 @@ def fs_event_setup(self): self.fname = '' self.q = asyncio.Queue() - def event_cb(self, ev_fname: bytes, evt: int): + def event_cb(self, ev_fname: bytes, evt: FileSystemEvent): _d, fn = os.path.split(self.fname) self.assertEqual(ev_fname, fn) - self.assertEqual(evt, FS_EVENT.CHANGE) + self.assertEqual(evt, FileSystemEvent.CHANGE) self.change_event_count += 1 if self.change_event_count < 4: self.q.put_nowait(0) @@ -44,11 +44,13 @@ async def run(write_task): with tempfile.NamedTemporaryFile('wt') as tf: self.fname = tf.name.encode() - h = self.loop.monitor_fs(tf.name, self.event_cb, False) + h = self.loop._monitor_fs(tf.name, self.event_cb) + self.assertFalse(h.cancelled()) try: self.loop.run_until_complete(run( self.loop.create_task(self._file_writer()))) - h.close() + h.cancel() + self.assertTrue(h.cancelled()) finally: self.loop.close() @@ -68,9 +70,9 @@ def fs_event_setup(self): self.changed_set = {self.changed_name, self.changed_name + '-new'} self.q = asyncio.Queue() - def event_cb(self, ev_fname: bytes, evt: int): + def event_cb(self, ev_fname: bytes, evt: FileSystemEvent): ev_fname = ev_fname.decode() - self.assertEqual(evt, FS_EVENT.RENAME) + self.assertEqual(evt, FileSystemEvent.RENAME) self.changed_set.remove(ev_fname) if len(self.changed_set) == 0: self.q.put_nowait(None) @@ -91,11 +93,13 @@ async def run(write_task): f = open(os.path.join(td_name, self.changed_name), 'wt') f.write('hello!') f.close() - h = self.loop.monitor_fs(td_name, self.event_cb, False) + h = self.loop._monitor_fs(td_name, self.event_cb) + self.assertFalse(h.cancelled()) try: self.loop.run_until_complete(run( self.loop.create_task(self._file_renamer()))) - h.close() + h.cancel() + self.assertTrue(h.cancelled()) finally: self.loop.close() diff --git a/tests/test_get_uvloop_ptr.py b/tests/test_get_uvloop_ptr.py deleted file mode 100644 index f1bb3cee..00000000 --- a/tests/test_get_uvloop_ptr.py +++ /dev/null @@ -1,18 +0,0 @@ -import uvloop -from uvloop import _testbase as tb -import ctypes -import os.path - - -class TestGetUvLoopPtr(tb.UVTestCase): - def test_get_uv_loop_ptr(self): - so_lib_path = None - dir_p = os.path.split(uvloop.__file__)[0] - for n in os.listdir(dir_p): - if n.endswith('.so'): - so_lib_path = os.path.join(dir_p, n) - if so_lib_path is None: - raise RuntimeError('could not find uvloop shared lib') - cdll = ctypes.CDLL(so_lib_path) - self.assertNotEqual(cdll.get_uv_loop_ptr(ctypes.py_object(self.loop)), - 0) diff --git a/uvloop/const.py b/uvloop/const.py deleted file mode 100644 index 82c0a350..00000000 --- a/uvloop/const.py +++ /dev/null @@ -1,6 +0,0 @@ -import enum - - -class FS_EVENT(enum.IntEnum): - CHANGE = 2 - RENAME = 1 diff --git a/uvloop/handles/fsevent.pxd b/uvloop/handles/fsevent.pxd index 6ccc82bf..3a324285 100644 --- a/uvloop/handles/fsevent.pxd +++ b/uvloop/handles/fsevent.pxd @@ -1,12 +1,12 @@ cdef class UVFSEvent(UVHandle): cdef: object callback + bint running - cdef _init(self, Loop loop, char* path, object callback, - int flags) - + cdef _init(self, Loop loop, object callback, object context) cdef _close(self) + cdef start(self, char* path, int flags) + cdef stop(self) @staticmethod - cdef UVFSEvent new(Loop loop, char* path, object callback, - int flags) + cdef UVFSEvent new(Loop loop, object callback, object context) diff --git a/uvloop/handles/fsevent.pyx b/uvloop/handles/fsevent.pyx index a835b50a..d0ca6e52 100644 --- a/uvloop/handles/fsevent.pyx +++ b/uvloop/handles/fsevent.pyx @@ -1,70 +1,111 @@ +import enum + + +class FileSystemEvent(enum.IntEnum): + RENAME = uv.UV_RENAME + CHANGE = uv.UV_CHANGE + + @cython.no_gc_clear cdef class UVFSEvent(UVHandle): - cdef _init(self, Loop loop, char* path, object callback, - int flags): - + cdef _init(self, Loop loop, object callback, object context): cdef int err self._start_init(loop) - self._handle = PyMem_RawMalloc(sizeof(uv.uv_fs_event_t)) + self._handle = PyMem_RawMalloc( + sizeof(uv.uv_fs_event_t) + ) if self._handle is NULL: self._abort_init() raise MemoryError() - err = uv.uv_fs_event_init(self._loop.uvloop, self._handle) - if err < 0: - self._abort_init() - raise convert_error(err) - - - err = uv.uv_fs_event_start(self._handle, __uvfsevent_callback, path, flags) + err = uv.uv_fs_event_init( + self._loop.uvloop, self._handle + ) if err < 0: self._abort_init() raise convert_error(err) self._finish_init() + self.running = 0 self.callback = callback + if context is None: + context = Context_CopyCurrent() + self.context = context + cdef start(self, char* path, int flags): + cdef int err - cdef _close(self): + self._ensure_alive() + + if self.running == 0: + err = uv.uv_fs_event_start( + self._handle, + __uvfsevent_callback, + path, + flags, + ) + if err < 0: + exc = convert_error(err) + self._fatal_error(exc, True) + return + self.running = 1 + + cdef stop(self): cdef int err if not self._is_alive(): + self.running = 0 return - err = uv.uv_fs_event_stop(self._handle) - if err < 0: - exc = convert_error(err) - self._fatal_error(exc, True) - return - - UVHandle._close(self) + if self.running == 1: + err = uv.uv_fs_event_stop(self._handle) + self.running = 0 + if err < 0: + exc = convert_error(err) + self._fatal_error(exc, True) + return + cdef _close(self): + try: + self.stop() + finally: + UVHandle._close(self) - def close(self): + def cancel(self): self._close() - @staticmethod - cdef UVFSEvent new(Loop loop, char* path, object callback, - int flags): + def cancelled(self): + return self.running == 0 + @staticmethod + cdef UVFSEvent new(Loop loop, object callback, object context): cdef UVFSEvent handle handle = UVFSEvent.__new__(UVFSEvent) - handle._init(loop, path, callback, flags) + handle._init(loop, callback, context) return handle cdef void __uvfsevent_callback(uv.uv_fs_event_t* handle, const char *filename, int events, int status) with gil: - if __ensure_handle_data(handle, "UVFSEvent callback") == 0: + if __ensure_handle_data( + handle, "UVFSEvent callback" + ) == 0: return cdef: UVFSEvent fs_event = handle.data + Handle h try: - fs_event.callback(filename, events) + h = new_Handle( + fs_event._loop, + fs_event.callback, + (filename, FileSystemEvent(events)), + fs_event.context, + ) + h._run() except BaseException as ex: fs_event._error(ex, False) diff --git a/uvloop/includes/uv.pxd b/uvloop/includes/uv.pxd index c0030c40..2f2f1e80 100644 --- a/uvloop/includes/uv.pxd +++ b/uvloop/includes/uv.pxd @@ -219,15 +219,10 @@ cdef extern from "uv.h" nogil: UV_LEAVE_GROUP = 0, UV_JOIN_GROUP - ctypedef enum uv_fs_event: + cpdef enum uv_fs_event: UV_RENAME = 1, UV_CHANGE = 2 - ctypedef enum uv_fs_event_flags: - UV_FS_EVENT_WATCH_ENTRY = 1, - UV_FS_EVENT_STAT = 2, - UV_FS_EVENT_RECURSIVE = 4 - const char* uv_strerror(int err) const char* uv_err_name(int err) @@ -266,7 +261,10 @@ cdef extern from "uv.h" nogil: const uv_buf_t* buf, const system.sockaddr* addr, unsigned flags) with gil - ctypedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, const char *filename, int events, int status) with gil + ctypedef void (*uv_fs_event_cb)(uv_fs_event_t* handle, + const char *filename, + int events, + int status) with gil # Generic request functions int uv_cancel(uv_req_t* req) @@ -414,7 +412,8 @@ cdef extern from "uv.h" nogil: # FS Event int uv_fs_event_init(uv_loop_t *loop, uv_fs_event_t *handle) - int uv_fs_event_start(uv_fs_event_t *handle, uv_fs_event_cb cb, const char *path, unsigned int flags) + int uv_fs_event_start(uv_fs_event_t *handle, uv_fs_event_cb cb, + const char *path, unsigned int flags) int uv_fs_event_stop(uv_fs_event_t *handle) # Misc diff --git a/uvloop/loop.pxd b/uvloop/loop.pxd index f6e76f33..2080dfe9 100644 --- a/uvloop/loop.pxd +++ b/uvloop/loop.pxd @@ -4,7 +4,7 @@ from .includes cimport uv from .includes cimport system -from libc.stdint cimport uint64_t, uint32_t, int64_t, uintptr_t +from libc.stdint cimport uint64_t, uint32_t, int64_t include "includes/consts.pxi" diff --git a/uvloop/loop.pyi b/uvloop/loop.pyi index 7e95232c..05d7714b 100644 --- a/uvloop/loop.pyi +++ b/uvloop/loop.pyi @@ -292,4 +292,3 @@ class Loop: *, fallback: bool = ... ) -> int: ... - def monitor_fs(self, path: str, callback: Callable[..., Any], flags: int) -> asyncio.Handle: ... diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index 9e57dad0..0008f188 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -3148,12 +3148,18 @@ cdef class Loop: await waiter return udp, protocol - def monitor_fs(self, path: str, callback, recursive: bool) -> asyncio.Handle: + def _monitor_fs(self, path: str, callback) -> asyncio.Handle: + cdef: + UVFSEvent fs_handle + char* c_str_path + self._check_closed() + fs_handle = UVFSEvent.new(self, callback, None) p_bytes = path.encode('UTF-8') - flags = 4 if recursive else 0 - cdef char* c_str_path = p_bytes - return UVFSEvent.new(self, c_str_path, callback, flags) + c_str_path = p_bytes + flags = 0 + fs_handle.start(c_str_path, flags) + return fs_handle def _check_default_executor(self): if self._executor_shutdown_called: @@ -3224,9 +3230,6 @@ cdef class Loop: return PyCapsule_New(self.uvloop, NULL, NULL) -cdef extern uv.uv_loop_t* get_uv_loop_ptr(PyObject* loop) nogil: - return (loop).uvloop - cdef void __loop_alloc_buffer(uv.uv_handle_t* uvhandle, size_t suggested_size, uv.uv_buf_t* buf) with gil: @@ -3320,8 +3323,6 @@ include "handles/udp.pyx" include "server.pyx" -DEF FS_EVENT_CHANGE = 2 -DEF FS_EVENT_RENAME = 1 # Used in UVProcess cdef vint __atfork_installed = 0 From 91def83770be0a4d9d235bf8d8cad1255c584a43 Mon Sep 17 00:00:00 2001 From: Fantix King Date: Mon, 5 Sep 2022 12:38:40 -0400 Subject: [PATCH 13/15] Allow both RENAME and CHANGE This happens when executing chmod on a subdir on Linux --- uvloop/handles/fsevent.pyx | 1 + 1 file changed, 1 insertion(+) diff --git a/uvloop/handles/fsevent.pyx b/uvloop/handles/fsevent.pyx index d0ca6e52..7b458c29 100644 --- a/uvloop/handles/fsevent.pyx +++ b/uvloop/handles/fsevent.pyx @@ -4,6 +4,7 @@ import enum class FileSystemEvent(enum.IntEnum): RENAME = uv.UV_RENAME CHANGE = uv.UV_CHANGE + RENAME_CHANGE = RENAME | CHANGE @cython.no_gc_clear From fe77faa0898745fd220c277e4cf2972e0d09cb3f Mon Sep 17 00:00:00 2001 From: Fantix King Date: Fri, 9 Sep 2022 09:28:47 -0400 Subject: [PATCH 14/15] CRF: optimize tests --- tests/test_fs_event.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/tests/test_fs_event.py b/tests/test_fs_event.py index 7284875a..743589b5 100644 --- a/tests/test_fs_event.py +++ b/tests/test_fs_event.py @@ -40,19 +40,16 @@ async def run(write_task): await asyncio.wait_for(write_task, 4) except asyncio.TimeoutError: write_task.cancel() - self.loop.stop() with tempfile.NamedTemporaryFile('wt') as tf: self.fname = tf.name.encode() h = self.loop._monitor_fs(tf.name, self.event_cb) self.assertFalse(h.cancelled()) - try: - self.loop.run_until_complete(run( - self.loop.create_task(self._file_writer()))) - h.cancel() - self.assertTrue(h.cancelled()) - finally: - self.loop.close() + + self.loop.run_until_complete(run( + self.loop.create_task(self._file_writer()))) + h.cancel() + self.assertTrue(h.cancelled()) self.assertEqual(self.change_event_count, 4) @@ -86,7 +83,6 @@ async def run(write_task): await asyncio.wait_for(write_task, 4) except asyncio.TimeoutError: write_task.cancel() - self.loop.stop() with tempfile.TemporaryDirectory() as td_name: self.dname = td_name @@ -95,12 +91,10 @@ async def run(write_task): f.close() h = self.loop._monitor_fs(td_name, self.event_cb) self.assertFalse(h.cancelled()) - try: - self.loop.run_until_complete(run( - self.loop.create_task(self._file_renamer()))) - h.cancel() - self.assertTrue(h.cancelled()) - finally: - self.loop.close() + + self.loop.run_until_complete(run( + self.loop.create_task(self._file_renamer()))) + h.cancel() + self.assertTrue(h.cancelled()) self.assertEqual(len(self.changed_set), 0) From 5658110528db756f599dae70ba11c4ae7f8daf33 Mon Sep 17 00:00:00 2001 From: Fantix King Date: Fri, 9 Sep 2022 10:04:58 -0400 Subject: [PATCH 15/15] Update pyOpenSSL to 22.x --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8425962c..486ea278 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,7 @@ 'flake8~=3.9.2', 'psutil', 'pycodestyle~=2.7.0', - 'pyOpenSSL~=19.0.0', + 'pyOpenSSL~=22.0.0', 'mypy>=0.800', CYTHON_DEPENDENCY, ]