diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 86823dc..54efa63 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,30 +1,30 @@ - ## ISSUE - + - [ ] bug - [ ] optimization idea ## TO REPRODUCE - - - - diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index bdfc7d3..7209d2b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,5 +1,5 @@ - @@ -31,7 +31,7 @@ entertain early in the review process. Thank you in advance! ## Checklist - - [ ] I think the code is well written diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 95df755..bb8face 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -1,6 +1,6 @@ -# Borrowed from pycares & cyares, -# this will be the nightly build I've -# been talking about adding for the past 2 years, +# Borrowed from pycares & cyares, +# this will be the nightly build I've +# been talking about adding for the past 2 years, # - Vizonex name: Build Wheels @@ -28,4 +28,4 @@ jobs: with: path: dist merge-multiple: true - - run: ls -lR dist \ No newline at end of file + - run: ls -lR dist diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml new file mode 100644 index 0000000..dc64425 --- /dev/null +++ b/.github/workflows/pre-commit.yml @@ -0,0 +1,19 @@ +name: Pre-commit + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + - uses: pre-commit/action@v3.0.1 diff --git a/.github/workflows/release-wheels.yml b/.github/workflows/release-wheels.yml index 8108922..33bfc67 100644 --- a/.github/workflows/release-wheels.yml +++ b/.github/workflows/release-wheels.yml @@ -7,7 +7,7 @@ on: types: - published -permissions: +permissions: contents: write jobs: diff --git a/.github/workflows/run-cibuildwheel.yml b/.github/workflows/run-cibuildwheel.yml index 924b930..e1eaed0 100644 --- a/.github/workflows/run-cibuildwheel.yml +++ b/.github/workflows/run-cibuildwheel.yml @@ -29,7 +29,7 @@ jobs: # Nb. keep cibuildwheel version pin consistent with job below run: pipx install cibuildwheel==3.2.1 - id: set-matrix - # Trimmed out setupmatrix for just windows but I might look at compiling other oses just for fun + # Trimmed out setupmatrix for just windows but I might look at compiling other oses just for fun # to let others test what it would be like if uvloop supported windows. It's very tempting... run: | MATRIX=$( diff --git a/.github/workflows/run-sdist.yml b/.github/workflows/run-sdist.yml index ad1e901..831b61c 100644 --- a/.github/workflows/run-sdist.yml +++ b/.github/workflows/run-sdist.yml @@ -19,11 +19,10 @@ jobs: - name: Install setuptools run: python -m pip install -U setuptools - name: Install Cython - run : python -m pip install cython + run : python -m pip install cython - name: Build sdist run: python setup.py sdist - uses: actions/upload-artifact@v7 with: name: sdist path: dist/*.tar.gz - \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index afb3fb1..d6fbbf9 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -32,17 +32,13 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install Requirements run: python -m pip install --upgrade setuptools wheel pip cython pytest aiohttp aiodns - + - name: Compile Winloop run: pip install -e . - + - name: run-tests env: COLOR: yes PIP_USER: 1 run: pytest -vv shell: bash - - - - diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..f7f8b19 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,29 @@ +# See https://pre-commit.com for usage and config reference. +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + + - repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + exclude: | + (?x)^( + vendor/.*| + .*\.pyc| + .*\.pyd| + .*\.so| + .*\.pyx\.c + )$ + args: + - --ignore-words-list=asince,bu,hist,nd,noe,ot,te,ue,wan,wile,ans,crate,cas,trough,conection,exection,fo,ist,nam,no,onot,pres,ser,set,start,uint,axcept,alloc,ba,cycl,fulllist,indx,isin,inout,les,ls,mut,nin,releated,sice,splited,unser,vas,wether,assertin,asend + + - repo: https://github.com/MarcoGorelli/cython-lint + rev: v0.16.0 + hooks: + - id: cython-lint + args: + - --no-pycodestyle diff --git a/LICENSE-APACHE b/LICENSE-APACHE index ae9d098..e3f3b32 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -200,4 +200,4 @@ Copyright (C) 2023-present Vizonex, the winloop authors and winloop contributors distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file + limitations under the License. diff --git a/README.md b/README.md index 5aa483d..a1f1207 100644 --- a/README.md +++ b/README.md @@ -252,8 +252,8 @@ if __name__ == "__main__": ## TODO-List -- [ ] In Winloop 0.2.0 or before 2026 I would like to start planning to migrate to pytest so that things could be formatted a little better. -A Migration Python script might be needed or looked into. +- [ ] In Winloop 0.2.0 or before 2026 I would like to start planning to migrate to pytest so that things could be formatted a little better. +A Migration Python script might be needed or looked into. - [ ] Update Fastapi Example to a more recent version of fastapi @@ -261,7 +261,7 @@ A Migration Python script might be needed or looked into. - [x] Nightly Builds And Test Suite Workflows for anyone wanting to use newer unreleased versions. (Done, it runs now) -- [ ] Adding in the necessary hooks for pyinstaller to compile this fast library to executable code even though hooks have been known to inflate the size of the `.exe` files. This is because calling hidden-imports for all the `__init__.py` modules might annoy some developers. (Luckily I'm aware of this issue because I've been doing this myself...) [Update, This is now pending and I hope that it passes](https://github.com/pyinstaller/pyinstaller-hooks-contrib/pull/867) +- [ ] Adding in the necessary hooks for pyinstaller to compile this fast library to executable code even though hooks have been known to inflate the size of the `.exe` files. This is because calling hidden-imports for all the `__init__.py` modules might annoy some developers. (Luckily I'm aware of this issue because I've been doing this myself...) [Update, This is now pending and I hope that it passes](https://github.com/pyinstaller/pyinstaller-hooks-contrib/pull/867) - [x] write a workflow for nightly builds if necessary for verification of pull requests. diff --git a/tests/test_process.py b/tests/test_process.py index ba4e819..b796491 100644 --- a/tests/test_process.py +++ b/tests/test_process.py @@ -460,7 +460,7 @@ async def main(n): for i in range(n): try: await asyncio.create_subprocess_exec( - "nonexistant", + "nonexistent", stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) diff --git a/tests/test_tcp.py b/tests/test_tcp.py index 7b0fe77..8b732e5 100644 --- a/tests/test_tcp.py +++ b/tests/test_tcp.py @@ -2292,7 +2292,7 @@ def server(sock): pass self.assertEqual(data, B_DATA) if conn.renegotiate_pending(): - conn.send(b"ERRO") + conn.send(b"ER") else: conn.send(b"SPAM") diff --git a/winloop/errors.pyx b/winloop/errors.pyx index 2f5624e..b49ddf6 100644 --- a/winloop/errors.pyx +++ b/winloop/errors.pyx @@ -10,7 +10,7 @@ cdef __convert_python_error(int uverr): # Implementation detail: on Unix error codes are the # negated errno (or -errno), while on Windows they # are defined by libuv to arbitrary negative numbers. - + cdef int oserr cdef object err @@ -20,10 +20,10 @@ cdef __convert_python_error(int uverr): # Winloop has a smarter technique for showing these errors. err = getattr(win_errno, uv.uv_err_name(uverr).decode(), uverr) return OSError(err, uv.uv_strerror(uverr).decode()) - + oserr = -uverr - + exc = OSError if uverr in (uv.UV_EACCES, uv.UV_EPERM): @@ -121,9 +121,9 @@ cdef convert_error(int uverr): sock_err = __convert_socket_error(uverr) if sock_err: - # Winloop comment: Sometimes libraries will throw in some + # Winloop comment: Sometimes libraries will throw in some # unwanted unicode BS to unravel, to prevent the possibility of this being a threat, - # surrogateescape is utilized + # surrogateescape is utilized # SEE: https://github.com/Vizonex/Winloop/issues/32 msg = system.gai_strerror(sock_err).decode('utf-8', "surrogateescape") # Winloop comment: on Windows, cPython has a simpler error @@ -134,7 +134,6 @@ cdef convert_error(int uverr): if sys_platform == "win32": if sock_err in (socket_EAI_FAMILY, socket_EAI_NONAME): msg = 'getaddrinfo failed' - return socket_gaierror(sock_err, msg) + return socket_gaierror(sock_err, msg) return __convert_python_error(uverr) - diff --git a/winloop/handles/process.pyx b/winloop/handles/process.pyx index 87ba15e..b82d186 100644 --- a/winloop/handles/process.pyx +++ b/winloop/handles/process.pyx @@ -91,7 +91,7 @@ cdef class UVProcess(UVHandle): self._restore_signals = restore_signals loop.active_process_handler = self - + if not system.PLATFORM_IS_WINDOWS: __forking = 1 @@ -101,12 +101,12 @@ cdef class UVProcess(UVHandle): PyOS_BeforeFork() else: py_gil_state = PyGILState_Ensure() - + err = uv.uv_spawn(loop.uvloop, self._handle, &self.options) - - + + if not system.PLATFORM_IS_WINDOWS: __forking = 0 __forking_loop = None @@ -115,7 +115,7 @@ cdef class UVProcess(UVHandle): PyOS_AfterFork_Parent() else: PyGILState_Release(py_gil_state) - + loop.active_process_handler = None @@ -439,7 +439,7 @@ cdef class UVProcessTransport(UVProcess): else: self._pending_calls.append((_CALL_PIPE_DATA_RECEIVED, fd, data)) - + cdef _file_redirect_stdio(self, int fd): fd = os_dup(fd) @@ -494,13 +494,13 @@ cdef class UVProcessTransport(UVProcess): 'subprocess.STDOUT is supported only by stderr parameter') else: io[0] = self._file_redirect_stdio(_stdin) - + elif system.PLATFORM_IS_WINDOWS and system.__UVLOOP_STDIN_BAD: - + # When a stdio is in a gui-like state without a console. # using a standard redirect is not a good idea. This at least - # is a better workaround that is a bit cleaner than doing what the - # python standard library subprocess does with the _get_handles function + # is a better workaround that is a bit cleaner than doing what the + # python standard library subprocess does with the _get_handles function # on windows. SEE: https://github.com/Vizonex/Winloop/issues/126 io[0] = self._file_devnull() @@ -559,7 +559,7 @@ cdef class UVProcessTransport(UVProcess): io[2] = self._file_devnull() else: io[2] = self._file_redirect_stdio(_stderr) - + elif system.PLATFORM_IS_WINDOWS and system.__UVLOOP_STDOUT_BAD: io[2] = self._file_devnull() else: @@ -817,7 +817,7 @@ cdef __socketpair(): int err # Winloop comment: no Unix sockets on Windows, using uv.uv_pipe() - # instead of system.socketpair(). Also, see changes to + # instead of system.socketpair(). Also, see changes to # libuv/src/win/pipe.c to deal with UV_EPERM = -4048 errors # for stdin pipe. if system.PLATFORM_IS_WINDOWS: diff --git a/winloop/handles/stream.pyx b/winloop/handles/stream.pyx index 974d6ab..5e63f6e 100644 --- a/winloop/handles/stream.pyx +++ b/winloop/handles/stream.pyx @@ -101,7 +101,6 @@ cdef class _StreamWriteContext: _StreamWriteContext ctx int uv_bufs_idx = 0 size_t py_bufs_len = 0 - int i Py_buffer* p_pybufs uv.uv_buf_t* p_uvbufs @@ -355,7 +354,7 @@ cdef class UVStream(UVBaseTransport): Py_ssize_t blen int saved_errno int fd - + if system.PLATFORM_IS_WINDOWS: # Winloop comment: WSASend below does not work with pipes. # For pipes, using Writefile() from Windows fileapi.h would @@ -445,7 +444,7 @@ cdef class UVStream(UVBaseTransport): cdef bint all_sent if (not self._protocol_paused and - (self._handle).write_queue_size == 0 and + (self._handle).write_queue_size == 0 and self._buffer_size > self._high_water): # Fast-path. If: # - the protocol isn't yet paused, @@ -693,12 +692,12 @@ cdef class UVStream(UVBaseTransport): cpdef write(self, object buf): self._ensure_alive() - + if system.PLATFORM_IS_WINDOWS: # Winloop Comment: Winloop gets itself into trouble if this is - # is not checked immediately, it's too costly to call the python function + # is not checked immediately, it's too costly to call the python function # bring in the flag instead to indicate closure. - # SEE: https://github.com/Vizonex/Winloop/issues/84 + # SEE: https://github.com/Vizonex/Winloop/issues/84 if self._closing: raise RuntimeError("Cannot call write() when UVStream is closing") diff --git a/winloop/includes/compat.h b/winloop/includes/compat.h index b82a20f..6e88931 100644 --- a/winloop/includes/compat.h +++ b/winloop/includes/compat.h @@ -159,7 +159,7 @@ _Py_RestoreSignals(void) #ifdef _WIN32 void PyOS_BeforeFork() { return; -} +} void PyOS_AfterFork_Parent() { return; } @@ -170,7 +170,7 @@ void PyOS_AfterFork_Child() { #ifdef _WIN32 -/* For some strange reason this structure does not want to show up +/* For some strange reason this structure does not want to show up * when compiling in debug mode on 3.13+ on windows so lets redefine it as a macro */ /* IDK How big to make this so will just leave it at 1 in case somehow accidentally exposed */ @@ -181,13 +181,13 @@ void PyOS_AfterFork_Child() { /* There is a bug with CX-Freeze on windows when compiled - * to an exe this tries to fix it by seeing if alternate - * workarounds like DEVNULL need to be provided. - * SEE: https://github.com/Vizonex/Winloop/issues/126 - * There are several alternate workarounds to the problem but - * what were going to attempt to do here is see if stdin, stdout, or stderr - * are all mapped properly to 0, 1, 2. If these are -2 then the implementation - * seen in subprocess.py will need to be applied where a handle is open with one closed + * to an exe this tries to fix it by seeing if alternate + * workarounds like DEVNULL need to be provided. + * SEE: https://github.com/Vizonex/Winloop/issues/126 + * There are several alternate workarounds to the problem but + * what were going to attempt to do here is see if stdin, stdout, or stderr + * are all mapped properly to 0, 1, 2. If these are -2 then the implementation + * seen in subprocess.py will need to be applied where a handle is open with one closed * off... */ #ifdef _WIN32 @@ -200,11 +200,9 @@ void PyOS_AfterFork_Child() { #else -/* On Unix these are not needed, but we define it anyways so the +/* On Unix these are not needed, but we define it anyways so the compiler doesn't wind up throwing a fit about it */ #define __UVLOOP_STDIN_BAD 0 #define __UVLOOP_STDOUT_BAD 0 #define __UVLOOP_STDERR_BAD 0 #endif - - diff --git a/winloop/includes/system.pxd b/winloop/includes/system.pxd index d2421b1..db132a1 100644 --- a/winloop/includes/system.pxd +++ b/winloop/includes/system.pxd @@ -69,7 +69,7 @@ cdef extern from "includes/compat.h" nogil: int __UVLOOP_STDIN_BAD int __UVLOOP_STDOUT_BAD int __UVLOOP_STDERR_BAD - + cdef extern from "includes/fork_handler.h": uint64_t MAIN_THREAD_ID @@ -89,12 +89,12 @@ cdef extern from "includes/fork_handler.h": cdef extern from * nogil: """ #ifdef _WIN32 -static inline uint64_t +static inline uint64_t __win_atomic_fetch_add(uint64_t *ptr, uint64_t val){ return *ptr = *(volatile uint64_t *)ptr + val; } -static inline uint64_t +static inline uint64_t __win_atomic_fetch_sub(uint64_t *ptr, uint64_t val){ return *ptr = *(volatile uint64_t *)ptr - val; } diff --git a/winloop/includes/uv.pxd b/winloop/includes/uv.pxd index 4ad45cb..8e824ce 100644 --- a/winloop/includes/uv.pxd +++ b/winloop/includes/uv.pxd @@ -231,7 +231,7 @@ cdef extern from "uv.h" nogil: const char* uv_strerror(int err) const char* uv_err_name(int err) - + # Needed on windows int uv_translate_sys_error(int sys_errno) @@ -496,7 +496,7 @@ cdef extern from "uv.h" nogil: ctypedef struct uv_stdio_container_t: uv_stdio_flags flags uv_stdio_container_data_u data - + ctypedef unsigned char uv_uid_t ctypedef unsigned char uv_gid_t diff --git a/winloop/loop.pyx b/winloop/loop.pyx index 47e7ea7..cb8686a 100644 --- a/winloop/loop.pyx +++ b/winloop/loop.pyx @@ -11,7 +11,6 @@ from .includes.python cimport ( PyMem_RawMalloc, PyMem_RawFree, PyMem_RawCalloc, PyMem_RawRealloc, PyUnicode_EncodeFSDefault, - PyErr_SetInterrupt, _Py_RestoreSignals, Context_CopyCurrent, Context_Enter, @@ -28,14 +27,12 @@ from libc.stdint cimport uint64_t from libc.string cimport memset, strerror, memcpy from libc cimport errno -# Winloop Comment: We need some cleaver hacky techniques for +# Winloop Comment: We need some cleaver hacky techniques for # preventing slow spawnning processes for MSVC -from cpython.pystate cimport (PyGILState_Ensure, PyGILState_Release, - PyGILState_STATE) -from cpython cimport PyObject -from cpython cimport PyErr_CheckSignals, PyErr_Occurred +from cpython.pystate cimport PyGILState_Ensure, PyGILState_Release +from cpython cimport PyErr_CheckSignals from cpython cimport PyThread_get_thread_ident -from cpython cimport Py_INCREF, Py_DECREF, Py_XDECREF, Py_XINCREF +from cpython cimport Py_INCREF, Py_DECREF from cpython cimport ( PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, Py_buffer, PyBytes_AsString, PyBytes_CheckExact, @@ -510,8 +507,6 @@ cdef class Loop: raise convert_error(err) cdef _run(self, uv.uv_run_mode mode): - cdef int err - if self._closed == 1: raise RuntimeError('unable to start the loop; it was closed') @@ -949,12 +944,12 @@ cdef class Loop: if fut.cancelled(): # Shouldn't happen with _SyncSocketReaderFuture. raise RuntimeError( - f'_sock_recv is called on a cancelled Future') + '_sock_recv is called on a cancelled Future') if not self._has_reader(sock): raise RuntimeError( f'socket {sock!r} does not have a reader ' - f'in the _sock_recv callback') + 'in the _sock_recv callback') try: data = sock.recv(n) @@ -976,12 +971,12 @@ cdef class Loop: if fut.cancelled(): # Shouldn't happen with _SyncSocketReaderFuture. raise RuntimeError( - f'_sock_recv_into is called on a cancelled Future') + '_sock_recv_into is called on a cancelled Future') if not self._has_reader(sock): raise RuntimeError( f'socket {sock!r} does not have a reader ' - f'in the _sock_recv_into callback') + 'in the _sock_recv_into callback') try: data = sock.recv_into(buf) @@ -1007,12 +1002,12 @@ cdef class Loop: if fut.cancelled(): # Shouldn't happen with _SyncSocketWriterFuture. raise RuntimeError( - f'_sock_sendall is called on a cancelled Future') + '_sock_sendall is called on a cancelled Future') if not self._has_writer(sock): raise RuntimeError( f'socket {sock!r} does not have a writer ' - f'in the _sock_sendall callback') + 'in the _sock_sendall callback') try: n = sock.send(data) @@ -1091,12 +1086,12 @@ cdef class Loop: if fut.cancelled(): # Shouldn't happen with _SyncSocketWriterFuture. raise RuntimeError( - f'_sock_connect_cb is called on a cancelled Future') + '_sock_connect_cb is called on a cancelled Future') if not self._has_writer(sock): raise RuntimeError( f'socket {sock!r} does not have a writer ' - f'in the _sock_connect_cb callback') + 'in the _sock_connect_cb callback') try: err = sock.getsockopt(uv.SOL_SOCKET, uv.SO_ERROR) @@ -2838,7 +2833,7 @@ cdef class Loop: comspec = os_path_join(system_root, 'System32', 'cmd.exe') if not os_path_isabs(comspec): raise FileNotFoundError('shell not found: neither %ComSpec% nor %SystemRoot% is set') - + args = [comspec] args.append('/c') args.append(cmd)