From e1575ec9e32a7d73ba4355107ede46922ca57314 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 4 Sep 2026 15:16:25 +0200 Subject: [PATCH 1/5] chore: compat python >= 3.10 --- python/Wiimote.c | 75 +++++++++++++++++++++++++++++++++++++----------- python/setup.py | 7 ++++- 2 files changed, 64 insertions(+), 18 deletions(-) diff --git a/python/Wiimote.c b/python/Wiimote.c index 6d18891..9703dfb 100644 --- a/python/Wiimote.c +++ b/python/Wiimote.c @@ -20,12 +20,24 @@ * */ +/* Must be defined before Python.h: lengths in the '#' argument-parsing + * formats are Py_ssize_t instead of int. Mandatory since python 3.10 -- + * always define it, whichever formats are used. */ +#define PY_SSIZE_T_CLEAN #include "Python.h" #include "structmember.h" #include +#include #include #include +/* The old buffer protocol (PyObject_AsWriteBuffer) is deprecated since python + * 3.0 and removed since 3.10: both ways of filling a buffer are kept below, + * selected at compile time so that the module builds against any python 3. */ +#if PY_VERSION_HEX < 0x030A0000 +#define CWIID_OLD_BUFFER_API 1 +#endif + typedef struct { PyObject_HEAD cwiid_wiimote_t *wiimote; @@ -208,9 +220,11 @@ static int Wiimote_init(Wiimote* self, PyObject* args, PyObject *kwds) bdaddr = *BDADDR_ANY; } - if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 5) { - PyEval_InitThreads(); - } +#if PY_VERSION_HEX < 0x03070000 + /* Deprecated since 3.9, no-op since 3.7: the GIL is always + initialized by Py_Initialize(). */ + PyEval_InitThreads(); +#endif Py_BEGIN_ALLOW_THREADS wiimote = cwiid_open(&bdaddr, flags); @@ -758,20 +772,23 @@ static PyObject *Wiimote_send_rpt(Wiimote *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = { "flags", "report", "buffer", NULL }; unsigned char flags, report; - void *buf; - int len; + Py_buffer buf; + int err; if (!self->wiimote) { SET_CLOSED_ERROR; return NULL; } - if (!PyArg_ParseTupleAndKeywords(args, kwds, "BBt#:cwiid.Wiimote.send_rpt", - kwlist, &flags, &report, &buf, &len)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "BBy*:cwiid.Wiimote.send_rpt", + kwlist, &flags, &report, &buf)) { return NULL; } - if (cwiid_send_rpt(self->wiimote, flags, report, len, buf)) { + err = cwiid_send_rpt(self->wiimote, flags, report, buf.len, buf.buf); + PyBuffer_Release(&buf); + if (err) { PyErr_SetString(PyExc_RuntimeError, "Error sending report"); return NULL; } @@ -784,9 +801,12 @@ static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds) static char *kwlist[] = { "flags", "offset", "len", NULL }; unsigned char flags; unsigned int offset; - Py_ssize_t len; + unsigned int len; void *buf; PyObject *pyRetBuf; +#ifdef CWIID_OLD_BUFFER_API + Py_ssize_t buf_len; +#endif if (!self->wiimote) { SET_CLOSED_ERROR; @@ -798,14 +818,25 @@ static PyObject *Wiimote_read(Wiimote *self, PyObject *args, PyObject *kwds) return NULL; } - if (!(pyRetBuf = malloc(len))) { + /* cwiid_read takes a uint16_t length: refuse what it cannot fill */ + if (len > UINT16_MAX) { + PyErr_SetString(PyExc_ValueError, "len too large"); + return NULL; + } + + /* mutable buffer, as advertised by the method docstring */ + if (!(pyRetBuf = PyByteArray_FromStringAndSize(NULL, len))) { return NULL; } - if (PyObject_AsWriteBuffer(pyRetBuf, &buf, &len)) { +#ifdef CWIID_OLD_BUFFER_API + if (PyObject_AsWriteBuffer(pyRetBuf, &buf, &buf_len)) { Py_DECREF(pyRetBuf); return NULL; } - if (cwiid_read(self->wiimote,flags,offset,len,buf)) { +#else + buf = PyByteArray_AS_STRING(pyRetBuf); +#endif + if (cwiid_read(self->wiimote, flags, offset, len, buf)) { PyErr_SetString(PyExc_RuntimeError, "Error reading wiimote data"); Py_DECREF(pyRetBuf); return NULL; @@ -819,20 +850,30 @@ static PyObject *Wiimote_write(Wiimote *self, PyObject *args, PyObject *kwds) static char *kwlist[] = { "flags", "offset", "buffer", NULL }; unsigned char flags; unsigned int offset; - void *buf; - int len; + Py_buffer buf; + int err; if (!self->wiimote) { SET_CLOSED_ERROR; return NULL; } - if (!PyArg_ParseTupleAndKeywords(args, kwds, "BIt#:cwiid.Wiimote.write", - kwlist, &flags, &offset, &buf, &len)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "BIy*:cwiid.Wiimote.write", + kwlist, &flags, &offset, &buf)) { + return NULL; + } + + /* cwiid_write takes a uint16_t length: refuse what it cannot send */ + if (buf.len > UINT16_MAX) { + PyBuffer_Release(&buf); + PyErr_SetString(PyExc_ValueError, "buffer too large"); return NULL; } - if (cwiid_write(self->wiimote, flags, offset, len, buf)) { + err = cwiid_write(self->wiimote, flags, offset, buf.len, buf.buf); + PyBuffer_Release(&buf); + if (err) { PyErr_SetString(PyExc_RuntimeError, "Error writing wiimote data"); return NULL; } diff --git a/python/setup.py b/python/setup.py index eb98019..f248542 100644 --- a/python/setup.py +++ b/python/setup.py @@ -1,4 +1,9 @@ -from distutils.core import setup, Extension +# distutils was removed from the standard library in python 3.12: prefer +# setuptools, fall back to distutils for older pythons without setuptools. +try: + from setuptools import setup, Extension +except ImportError: + from distutils.core import setup, Extension setup( name='cwiid', From 15c97e7fedc868a2983417dc9ff7d19212bc98f5 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 4 Sep 2026 15:16:59 +0200 Subject: [PATCH 2/5] qa: delete travis ci --- .travis.yml | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d8dcfb6..0000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: python - -before_install: - - sudo apt-get -qq update - - sudo apt-get install -y libbluetooth-dev - -python: - - "3.2" - - "3.3" - - "3.4" - - "3.5" - - "3.5-dev" - - "3.6" - - "3.6-dev" - - "3.7-dev" - - "nightly" - -script: - - | - aclocal - autoconf - ./configure - make - cd libcwiid/ - sudo make install - cd ../python/ - python setup.py install - python -c 'import cwiid' From 08e49d7dd8212017d85ab1592e5879c1870568d8 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 4 Sep 2026 15:22:43 +0200 Subject: [PATCH 3/5] config: fix python version detection --- configure.ac | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 5f34940..2a4dc88 100644 --- a/configure.ac +++ b/configure.ac @@ -33,15 +33,19 @@ AC_ARG_WITH( ;; esac], [REQUIRE_PYTHON=1; PYTHON_NAME=python3]) -if test $REQUIRE_PYTHON; then +if test -n "$REQUIRE_PYTHON"; then AC_CHECK_PROGS([PYTHON],$PYTHON_NAME) - if test $REQUIRE_PYTHON -a ! $PYTHON; then + if test -z "$PYTHON"; then AC_MSG_ERROR([$PYTHON_NAME not found]) fi fi AC_SUBST(PYTHON) -if test $PYTHON; then - PYTHON_VERSION=[`$PYTHON -c 'import sys; print(sys.version[:3])'`] +if test -n "$PYTHON"; then + dnl sys.version[:3] gives "3.1" for 3.10 and later: ask for the version + dnl fields instead of slicing the version string + AC_MSG_CHECKING([python version]) + PYTHON_VERSION=`$PYTHON -c 'import sys; print("%d.%d" % (sys.version_info.major, sys.version_info.minor))'` + AC_MSG_RESULT([$PYTHON_VERSION]) AC_SUBST(PYTHON_VERSION) AC_DEFINE([HAVE_PYTHON],1,[Define to 1 if python support is enabled]) fi From 0815fccb87ce5e8cc6fcdfad9c08d6e483e8d108 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 4 Sep 2026 15:24:08 +0200 Subject: [PATCH 4/5] qa: add github workflow --- .github/workflows/build.yml | 80 +++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..af0a730 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,80 @@ +name: build + +on: + push: + branches: [master] + pull_request: + workflow_dispatch: + +jobs: + build: + # 3.9 exercises the pre-3.10 buffer API branch of python/Wiimote.c, + # the other versions the modern one. + name: python ${{ matrix.python-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] + + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install build dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends \ + libbluetooth-dev flex bison + + # setuptools is not bundled with python 3.12+, and setup.py needs it + # since distutils was dropped from the standard library + - name: Install python build dependencies + run: python -m pip install --upgrade pip setuptools + + - name: Generate configure + run: aclocal && autoconf + + - name: Configure + run: ./configure + + - name: Build + run: make + + - name: Smoke test + run: | + export LD_LIBRARY_PATH="$PWD/libcwiid" + export PYTHONPATH="$(echo python/build/lib.*)" + python - <<'EOF' + import cwiid + + print('loaded', cwiid.__file__) + + # the extension exposes the type and the CWIID_* constants + for name in ('BTN_A', 'RPT_BTN', 'MESG_ACC', 'FLAG_MESG_IFC', + 'IR_X_MAX'): + assert isinstance(getattr(cwiid, name), int), name + + for name in ('close', 'enable', 'disable', 'get_mesg', 'read', + 'write', 'send_rpt', 'request_status'): + assert callable(getattr(cwiid.Wiimote, name)), name + + # no wiimote here: check the methods are callable and reject a + # closed connection instead of crashing + wiimote = cwiid.Wiimote.__new__(cwiid.Wiimote) + for call in (lambda: wiimote.read(0, 0, 4), + lambda: wiimote.write(0, 0, b'ab'), + lambda: wiimote.send_rpt(0, 0, b'ab'), + lambda: wiimote.close()): + try: + call() + except ValueError as err: + assert 'closed' in str(err), err + else: + raise AssertionError('expected a closed Wiimote error') + + print('smoke test ok') + EOF From 800be67854fce50f21846b7d63aaf07cb8c97c94 Mon Sep 17 00:00:00 2001 From: tom Date: Fri, 4 Sep 2026 16:16:22 +0200 Subject: [PATCH 5/5] doc: update doc --- CHANGELOG | 4 ++++ README.md | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index bdda3f6..c5e94ba 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +2017-03-19 azzra + project + * compatibility with Python 3.10+ + 2017-03-19 azzra project * remove lswm, wmdemo, wminput, wmgui diff --git a/README.md b/README.md index 6140cbc..df907cb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # CWiid Wiimote Interface -[![Build Status](https://travis-ci.org/azzra/python3-wiimote.svg?branch=master)](https://travis-ci.org/azzra/python3-wiimote) - ## DESCRIPTION The CWiid package contains the following parts: @@ -26,7 +24,7 @@ make Install the library with package manager & the extension from the sources ```sh -apt-get install libcwiid1 +apt install libcwiid1 cd python sudo make install ```