From 639661074b67cf280c554e55ba2b4557e58d9756 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 22 Nov 2025 15:14:26 +0100 Subject: [PATCH 1/4] Apply ruff/Pylint rule PLR0402 PLR0402 Use `from ... import ...` in lieu of alias --- testing/cffi1/test_pkgconfig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/cffi1/test_pkgconfig.py b/testing/cffi1/test_pkgconfig.py index 3dfed136..5b023cac 100644 --- a/testing/cffi1/test_pkgconfig.py +++ b/testing/cffi1/test_pkgconfig.py @@ -1,7 +1,7 @@ import sys import subprocess import pytest -import cffi.pkgconfig as pkgconfig +from cffi import pkgconfig from cffi import PkgConfigError From 3e91fd2690125c3f6e33e75aba80a61cc0422178 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 22 Nov 2025 15:15:06 +0100 Subject: [PATCH 2/4] Apply ruff/Pylint rule PLR1711 PLR1711 Useless `return` statement at end of function --- demo/_curses.py | 8 -------- src/cffi/backend_ctypes.py | 1 - 2 files changed, 9 deletions(-) diff --git a/demo/_curses.py b/demo/_curses.py index 60a21e8f..0e52f7ed 100644 --- a/demo/_curses.py +++ b/demo/_curses.py @@ -329,17 +329,14 @@ def bkgdset(self, ch, attr=None): if attr is None: attr = lib.A_NORMAL lib.wbkgdset(self._win, _chtype(ch) | attr) - return None def border(self, ls=0, rs=0, ts=0, bs=0, tl=0, tr=0, bl=0, br=0): lib.wborder(self._win, _chtype(ls), _chtype(rs), _chtype(ts), _chtype(bs), _chtype(tl), _chtype(tr), _chtype(bl), _chtype(br)) - return None def box(self, vertint=0, horint=0): lib.box(self._win, vertint, horint) - return None @_argspec(1, 1, 2) def chgat(self, y, x, num, attr=None): @@ -650,7 +647,6 @@ def vline(self, y, x, ch, n, attr=None): def filter(): lib.filter() - return None def color_content(color): @@ -913,7 +909,6 @@ def qiflush(flag=True): lib.qiflush() else: lib.noqiflush() - return None # XXX: Do something about the following? @@ -1016,7 +1011,6 @@ def qiflush(flag=True): def setsyx(y, x): _ensure_initialised() lib.setsyx(y, x) - return None def start_color(): @@ -1024,7 +1018,6 @@ def start_color(): globals()["COLORS"] = lib.COLORS globals()["COLOR_PAIRS"] = lib.COLOR_PAIRS globals()["_initialised_color"] = True - return None def tigetflag(capname): @@ -1070,7 +1063,6 @@ def ungetch(ch): def use_env(flag): lib.use_env(flag) - return None if not lib._m_STRICT_SYSV_CURSES: diff --git a/src/cffi/backend_ctypes.py b/src/cffi/backend_ctypes.py index 0801fc8e..72eda5bc 100644 --- a/src/cffi/backend_ctypes.py +++ b/src/cffi/backend_ctypes.py @@ -336,7 +336,6 @@ def _to_ctypes(novalue): if novalue is not None: raise TypeError("None expected, got %s object" % (type(novalue).__name__,)) - return None CTypesVoid._fix_class() return CTypesVoid From 53828d85c2000f8d6c6e4f51433ebf370fd09026 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 22 Nov 2025 15:21:29 +0100 Subject: [PATCH 3/4] Apply ruff/Pylint rule PLR1714 PLR1714 Consider merging multiple comparisons --- demo/bsdopendirtype.py | 2 +- demo/readdir.py | 2 +- demo/readdir2.py | 2 +- demo/readdir_ctypes.py | 2 +- demo/recopendirtype.py | 2 +- src/cffi/backend_ctypes.py | 10 +++++----- testing/cffi0/backend_tests.py | 2 +- testing/cffi0/test_verify.py | 6 +++--- testing/cffi1/test_ffi_obj.py | 4 ++-- testing/cffi1/test_new_ffi_1.py | 2 +- testing/cffi1/test_verify1.py | 6 +++--- 11 files changed, 20 insertions(+), 20 deletions(-) diff --git a/demo/bsdopendirtype.py b/demo/bsdopendirtype.py index 283e33dc..6bfdd3ab 100644 --- a/demo/bsdopendirtype.py +++ b/demo/bsdopendirtype.py @@ -33,7 +33,7 @@ def opendir(dir): raise _posix_error() return name = ffi.string(dirent.d_name) - if name == b'.' or name == b'..': + if name in {b'.', b'..'}: continue name = dirname + name try: diff --git a/demo/readdir.py b/demo/readdir.py index fcb2b7d9..77e39a5b 100644 --- a/demo/readdir.py +++ b/demo/readdir.py @@ -26,7 +26,7 @@ def walk(basefd, path): break name = ffi.string(dirent.d_name) print('%3d %s' % (dirent.d_type, name)) - if dirent.d_type == 4 and name != '.' and name != '..': + if dirent.d_type == 4 and name not in {'.', '..'}: walk(dirfd, name) lib.closedir(dir) print('}') diff --git a/demo/readdir2.py b/demo/readdir2.py index 7aef3289..7ed54087 100644 --- a/demo/readdir2.py +++ b/demo/readdir2.py @@ -26,7 +26,7 @@ def walk(basefd, path): break name = ffi.string(dirent.d_name) print('%3d %s' % (dirent.d_type, name)) - if dirent.d_type == lib.DT_DIR and name != '.' and name != '..': + if dirent.d_type == lib.DT_DIR and name not in {'.', '..'}: walk(dirfd, name) lib.closedir(dir) print('}') diff --git a/demo/readdir_ctypes.py b/demo/readdir_ctypes.py index 9ceb5298..39025f54 100644 --- a/demo/readdir_ctypes.py +++ b/demo/readdir_ctypes.py @@ -60,7 +60,7 @@ def walk(basefd, path): break name = dirent.d_name print('%3d %s' % (dirent.d_type, name)) - if dirent.d_type == 4 and name != '.' and name != '..': + if dirent.d_type == 4 and name not in {'.', '..'}: walk(dirfd, name) closedir(dir) print('}') diff --git a/demo/recopendirtype.py b/demo/recopendirtype.py index e22f92e9..aff3ce9a 100644 --- a/demo/recopendirtype.py +++ b/demo/recopendirtype.py @@ -35,7 +35,7 @@ def opendir(dir): if result[0] == ffi.NULL: return # name = ffi.string(dirent.d_name) - if name == b'.' or name == b'..': + if name in {b'.', b'..'}: continue name = dirname + name try: diff --git a/src/cffi/backend_ctypes.py b/src/cffi/backend_ctypes.py index 72eda5bc..12cd1625 100644 --- a/src/cffi/backend_ctypes.py +++ b/src/cffi/backend_ctypes.py @@ -386,7 +386,7 @@ def _create_ctype_obj(init): return ctype() return ctype(CTypesPrimitive._to_ctypes(init)) - if kind == 'int' or kind == 'byte': + if kind in {'int', 'byte'}: @classmethod def _cast_from(cls, source): source = _cast_source_to_int(source) @@ -434,7 +434,7 @@ def __float__(self): _cast_to_integer = __int__ - if kind == 'int' or kind == 'byte' or kind == 'bool': + if kind in {'int', 'byte', 'bool'}: @staticmethod def _to_ctypes(x): if not isinstance(x, (int, long)): @@ -557,7 +557,7 @@ def __getitem__(self, index): def __setitem__(self, index, value): self._as_ctype_ptr[index] = BItem._to_ctypes(value) - if kind == 'charp' or kind == 'voidp': + if kind in {'charp', 'voidp'}: @classmethod def _arg_to_ctypes(cls, *value): if value and isinstance(value[0], bytes): @@ -565,7 +565,7 @@ def _arg_to_ctypes(cls, *value): else: return super()._arg_to_ctypes(*value) - if kind == 'charp' or kind == 'bytep': + if kind in {'charp', 'bytep'}: def _to_string(self, maxlen): if maxlen < 0: maxlen = sys.maxsize @@ -662,7 +662,7 @@ def __setitem__(self, index, value): raise IndexError self._blob[index] = BItem._to_ctypes(value) - if kind == 'char' or kind == 'byte': + if kind in {'char', 'byte'}: def _to_string(self, maxlen): if maxlen < 0: maxlen = len(self._blob) diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py index 99b30316..ce11044d 100644 --- a/testing/cffi0/backend_tests.py +++ b/testing/cffi0/backend_tests.py @@ -33,7 +33,7 @@ def test_integer_ranges(self): c_decl = {None: '', False: 'signed ', True: 'unsigned '}[unsigned] + c_type - if c_decl == 'char' or c_decl == '': + if c_decl in {'char', ''}: continue self._test_int_type(ffi, c_decl, size, unsigned) diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py index f7a9c881..21e77028 100644 --- a/testing/cffi0/test_verify.py +++ b/testing/cffi0/test_verify.py @@ -251,7 +251,7 @@ def test_all_integer_and_float_types(): for typename in all_primitive_types: if (all_primitive_types[typename] == 'c' or all_primitive_types[typename] == 'j' or # complex - typename == '_Bool' or typename == 'long double'): + typename in {'_Bool', 'long double'}): pass else: typenames.append(typename) @@ -1665,7 +1665,7 @@ def test_FILE_stored_in_stdout(): os.close(fdr) # the 'X' might remain in the user-level buffer of 'fw1' and # end up showing up after the 'hello, 42!\n' - assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX" + assert result in {b"Xhello, 42!\n", b"hello, 42!\nX"} def test_FILE_stored_explicitly(): ffi = FFI() @@ -1691,7 +1691,7 @@ def test_FILE_stored_explicitly(): os.close(fdr) # the 'X' might remain in the user-level buffer of 'fw1' and # end up showing up after the 'hello, 42!\n' - assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX" + assert result in {b"Xhello, 42!\n", b"hello, 42!\nX"} def test_global_array_with_missing_length(): ffi = FFI() diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py index 0914ead5..b822636f 100644 --- a/testing/cffi1/test_ffi_obj.py +++ b/testing/cffi1/test_ffi_obj.py @@ -387,8 +387,8 @@ def myfree(raw): retries += 1 assert retries <= 5 import gc; gc.collect() - assert (seen == [40, 40, raw1, raw2] or - seen == [40, 40, raw2, raw1]) + assert seen in ([40, 40, raw1, raw2], + [40, 40, raw2, raw1]) assert repr(seen[2]) == "" assert repr(seen[3]) == "" diff --git a/testing/cffi1/test_new_ffi_1.py b/testing/cffi1/test_new_ffi_1.py index 676d235d..e0592c34 100644 --- a/testing/cffi1/test_new_ffi_1.py +++ b/testing/cffi1/test_new_ffi_1.py @@ -113,7 +113,7 @@ def test_integer_ranges(self): c_decl = {None: '', False: 'signed ', True: 'unsigned '}[unsigned] + c_type - if c_decl == 'char' or c_decl == '': + if c_decl in {'char', ''}: continue self._test_int_type(ffi, c_decl, size, unsigned) diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py index e8ffabd3..7bd3e129 100644 --- a/testing/cffi1/test_verify1.py +++ b/testing/cffi1/test_verify1.py @@ -228,7 +228,7 @@ def test_all_integer_and_float_types(): for typename in all_primitive_types: if (all_primitive_types[typename] == 'c' or all_primitive_types[typename] == 'j' or # complex - typename == '_Bool' or typename == 'long double'): + typename in {'_Bool', 'long double'}): pass else: typenames.append(typename) @@ -1629,7 +1629,7 @@ def test_FILE_stored_in_stdout(): os.close(fdr) # the 'X' might remain in the user-level buffer of 'fw1' and # end up showing up after the 'hello, 42!\n' - assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX" + assert result in {b"Xhello, 42!\n", b"hello, 42!\nX"} def test_FILE_stored_explicitly(): ffi = FFI() @@ -1655,7 +1655,7 @@ def test_FILE_stored_explicitly(): os.close(fdr) # the 'X' might remain in the user-level buffer of 'fw1' and # end up showing up after the 'hello, 42!\n' - assert result == b"Xhello, 42!\n" or result == b"hello, 42!\nX" + assert result in {b"Xhello, 42!\n", b"hello, 42!\nX"} def test_global_array_with_missing_length(): ffi = FFI() From cf1e77e96b4dfefc0384bea809fed0043f6c72fd Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 22 Nov 2025 15:24:41 +0100 Subject: [PATCH 4/4] Apply ruff/Pylint rule PLR5501 PLR5501 Use `elif` instead of `else` then `if`, to reduce indentation --- src/c/test_c.py | 15 +++++++-------- src/cffi/cparser.py | 9 ++++----- testing/cffi0/test_zdistutils.py | 5 ++--- testing/cffi1/test_function_args.py | 7 +++---- testing/support.py | 25 ++++++++++++------------- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/c/test_c.py b/src/c/test_c.py index 8d2228c1..b953464f 100644 --- a/src/c/test_c.py +++ b/src/c/test_c.py @@ -3366,15 +3366,14 @@ def _test_bitfield_details(flag): assert raw == b'A\xE3\x9B\x9D' else: raise AssertionError("bad flag") + elif flag & SF_MSVC_BITFIELDS: + assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00' + elif flag & SF_GCC_LITTLE_ENDIAN: + assert raw == b'A\xC77\x9D' + elif flag & SF_GCC_BIG_ENDIAN: + assert raw == b'A\x9B\xE3\x9D' else: - if flag & SF_MSVC_BITFIELDS: - assert raw == b'A\x00\x00\x00\x00\x00\xC77\x9D\x00\x00\x00' - elif flag & SF_GCC_LITTLE_ENDIAN: - assert raw == b'A\xC77\x9D' - elif flag & SF_GCC_BIG_ENDIAN: - assert raw == b'A\x9B\xE3\x9D' - else: - raise AssertionError("bad flag") + raise AssertionError("bad flag") # BStruct = new_struct_type("struct foo2") complete_struct_or_union(BStruct, [('a', BChar, -1), diff --git a/src/cffi/cparser.py b/src/cffi/cparser.py index 2d78fc4b..1896b7ef 100644 --- a/src/cffi/cparser.py +++ b/src/cffi/cparser.py @@ -804,11 +804,10 @@ def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): raise AssertionError("kind = %r" % (kind,)) if name is not None: self._declare(key, tp) - else: - if kind == 'enum' and type.values is not None: - raise NotImplementedError( - "enum %s: the '{}' declaration should appear on the first " - "time the enum is mentioned, not later" % explicit_name) + elif kind == 'enum' and type.values is not None: + raise NotImplementedError( + "enum %s: the '{}' declaration should appear on the first " + "time the enum is mentioned, not later" % explicit_name) if not tp.forcename: tp.force_the_name(force_name) if tp.forcename and '$' in tp.name: diff --git a/testing/cffi0/test_zdistutils.py b/testing/cffi0/test_zdistutils.py index c4b2db14..98b27734 100644 --- a/testing/cffi0/test_zdistutils.py +++ b/testing/cffi0/test_zdistutils.py @@ -31,12 +31,11 @@ def test_locate_engine_class(self): # asked for the generic engine, which must not generate a # CPython extension module assert not cls._gen_python_module - else: + elif '__pypy__' not in sys.builtin_module_names: # asked for the CPython engine: check that we got it, unless # we are running on top of PyPy, where the generic engine is # always better - if '__pypy__' not in sys.builtin_module_names: - assert cls._gen_python_module + assert cls._gen_python_module def test_write_source(self): ffi = FFI() diff --git a/testing/cffi1/test_function_args.py b/testing/cffi1/test_function_args.py index 38816e0f..daf3e644 100644 --- a/testing/cffi1/test_function_args.py +++ b/testing/cffi1/test_function_args.py @@ -158,11 +158,10 @@ def check(p, v): if type(v) is list: for i, v1 in enumerate(v): check(ffi.addressof(p, 'f%d' % i), v1) + elif ffi.typeof(p).item is _tp_long_double: + assert ffi.cast("double", p[0]) == v else: - if ffi.typeof(p).item is _tp_long_double: - assert ffi.cast("double", p[0]) == v - else: - assert p[0] == v + assert p[0] == v for i, arg in enumerate(passed_args): check(ffi.addressof(lib, 'testfargs_arg%d' % i), arg) diff --git a/testing/support.py b/testing/support.py index 382102ab..4f43c2f8 100644 --- a/testing/support.py +++ b/testing/support.py @@ -103,20 +103,19 @@ def typeof_disabled(*args, **kwds): if sys.platform == 'win32': extra_compile_args = [] # no obvious -Werror equivalent on MSVC +elif (sys.platform == 'darwin' and + [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]): + # assume a standard clang or gcc + extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion', + '-Wno-unused-parameter', + '-Wno-unreachable-code'] + # special things for clang + extra_compile_args.append('-Qunused-arguments') else: - if (sys.platform == 'darwin' and - [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]): - # assume a standard clang or gcc - extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion', - '-Wno-unused-parameter', - '-Wno-unreachable-code'] - # special things for clang - extra_compile_args.append('-Qunused-arguments') - else: - # assume a standard gcc - extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion', - '-Wno-unused-parameter', - '-Wno-unreachable-code'] + # assume a standard gcc + extra_compile_args = ['-Werror', '-Wall', '-Wextra', '-Wconversion', + '-Wno-unused-parameter', + '-Wno-unreachable-code'] is_musl = False if sys.platform == 'linux':