Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-aiocsv for openSUSE:Factory checked in at 2026-06-15 19:41:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-aiocsv (Old) and /work/SRC/openSUSE:Factory/.python-aiocsv.new.1981 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-aiocsv" Mon Jun 15 19:41:56 2026 rev:5 rq:1359218 version:1.4.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-aiocsv/python-aiocsv.changes 2025-09-29 16:37:36.923985882 +0200 +++ /work/SRC/openSUSE:Factory/.python-aiocsv.new.1981/python-aiocsv.changes 2026-06-15 19:44:52.627017801 +0200 @@ -1,0 +2,8 @@ +Sun Jun 14 09:34:43 UTC 2026 - Dirk Müller <[email protected]> + +- update to 1.4.1: + * python 3.14 and free-threading + * Prevent _parser.Parser from being shared across threads + * Add missing Py_CLEAR(Parser->buffer_str) + +------------------------------------------------------------------- Old: ---- aiocsv-1.4.0.tar.gz New: ---- aiocsv-1.4.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-aiocsv.spec ++++++ --- /var/tmp/diff_new_pack.s84XRH/_old 2026-06-15 19:44:53.367048812 +0200 +++ /var/tmp/diff_new_pack.s84XRH/_new 2026-06-15 19:44:53.371048979 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-aiocsv # -# Copyright (c) 2025 SUSE LLC and contributors +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?sle15_python_module_pythons} Name: python-aiocsv -Version: 1.4.0 +Version: 1.4.1 Release: 0 Summary: Asynchronous CSV reading/writing in Python License: MIT ++++++ aiocsv-1.4.0.tar.gz -> aiocsv-1.4.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiocsv-1.4.0/.github/workflows/deploy.yml new/aiocsv-1.4.1/.github/workflows/deploy.yml --- old/aiocsv-1.4.0/.github/workflows/deploy.yml 2025-09-22 14:04:03.000000000 +0200 +++ new/aiocsv-1.4.1/.github/workflows/deploy.yml 2026-05-22 19:43:28.000000000 +0200 @@ -22,6 +22,7 @@ env: CIBW_ARCHS: auto CIBW_BUILD: cp3*-* + CIBW_ENABLE: cpython-freethreading - uses: actions/upload-artifact@v4 with: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiocsv-1.4.0/.github/workflows/test.yml new/aiocsv-1.4.1/.github/workflows/test.yml --- old/aiocsv-1.4.0/.github/workflows/test.yml 2025-09-22 14:04:03.000000000 +0200 +++ new/aiocsv-1.4.1/.github/workflows/test.yml 2026-05-22 19:43:28.000000000 +0200 @@ -6,7 +6,7 @@ runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13", "3.13t", "3.14", "3.14t"] steps: - uses: actions/checkout@v5 - name: Set up Python ${{ matrix.python-version }} @@ -24,17 +24,17 @@ runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - - name: Set up Python 3.9 + - name: Set up Python 3.10 uses: actions/setup-python@v6 with: - python-version: "3.9" + python-version: "3.10" - name: Install dependencies - run: pip install -Ur requirements.dev.txt + run: pip install -U aiofiles pytest pytest-asyncio setuptools wheel - name: Check code formatting - run: black --check . - - name: Check imports order - run: isort --check . + uses: astral-sh/[email protected] - name: Install the library run: pip install -e . - - name: Run typechecking - run: pyright + - name: Type Check Python + uses: jakebailey/pyright-action@v3 + with: + pylance-version: latest-release diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiocsv-1.4.0/LICENSE new/aiocsv-1.4.1/LICENSE --- old/aiocsv-1.4.0/LICENSE 2025-09-22 14:04:03.000000000 +0200 +++ new/aiocsv-1.4.1/LICENSE 2026-05-22 19:43:28.000000000 +0200 @@ -1,5 +1,5 @@ -Copyright 2020-2024 Mikołaj Kuranowski +Copyright 2020-2026 Mikołaj Kuranowski Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiocsv-1.4.0/aiocsv/__init__.py new/aiocsv-1.4.1/aiocsv/__init__.py --- old/aiocsv-1.4.0/aiocsv/__init__.py 2025-09-22 14:04:03.000000000 +0200 +++ new/aiocsv-1.4.1/aiocsv/__init__.py 2026-05-22 19:43:28.000000000 +0200 @@ -1,15 +1,15 @@ -# © Copyright 2020-2024 Mikołaj Kuranowski +# © Copyright 2020-2026 Mikołaj Kuranowski # SPDX-License-Identifier: MIT __title__ = "aiocsv" __description__ = "Asynchronous CSV reading/writing" -__version__ = "1.4.0" +__version__ = "1.4.1" __url__ = "https://github.com/MKuranowski/aiocsv" __author__ = "Mikołaj Kuranowski" __email__ = "[email protected]" -__copyright__ = "© Copyright 2020-2024 Mikołaj Kuranowski" +__copyright__ = "© Copyright 2020-2026 Mikołaj Kuranowski" __license__ = "MIT" from .readers import AsyncDictReader, AsyncReader diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiocsv-1.4.0/aiocsv/_parser.c new/aiocsv-1.4.1/aiocsv/_parser.c --- old/aiocsv-1.4.0/aiocsv/_parser.c 2025-09-22 14:04:03.000000000 +0200 +++ new/aiocsv-1.4.1/aiocsv/_parser.c 2026-05-22 19:43:28.000000000 +0200 @@ -1,4 +1,4 @@ -// © Copyright 2020-2025 Mikołaj Kuranowski +// © Copyright 2020-2026 Mikołaj Kuranowski // SPDX-License-Identifier: MIT #include <assert.h> @@ -23,71 +23,6 @@ // * PYTHON API BACKPORTS * // ************************ -#if PY_VERSION_HEX < 0x030A0000 - -#define Py_TPFLAGS_IMMUTABLETYPE 0 -#define Py_TPFLAGS_DISALLOW_INSTANTIATION 0 - -typedef enum { - PYGEN_RETURN = 0, - PYGEN_ERROR = -1, - PYGEN_NEXT = 1, -} PySendResult; - -static inline PyObject* Py_NewRef(PyObject* o) { - Py_INCREF(o); - return o; -} - -static PyObject* _fetch_stop_iteration_value(void) { - PyObject* exc_type; - PyObject* exc_value; - PyObject* exc_traceback; - PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); - - assert(exc_type); - assert(PyErr_ExceptionMatches(PyExc_StopIteration)); - - PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback); - assert(PyObject_TypeCheck(exc_value, (PyTypeObject*)PyExc_StopIteration)); - - PyErr_Clear(); - - PyObject* value = ((PyStopIterationObject*)exc_value)->value; - Py_INCREF(value); - Py_XDECREF(exc_type); - Py_XDECREF(exc_value); - Py_XDECREF(exc_traceback); - return value; -} - -static PySendResult PyIter_Send(PyObject* iter, PyObject* arg, PyObject** presult) { - assert(arg); - assert(presult); - - // Ensure arg is Py_None - if (arg != Py_None) { - PyErr_SetString( - PyExc_SystemError, - "aiocsv's PyIter_Send backport doesn't support sending values other than None"); - return PYGEN_ERROR; - } - - // Ensure iter is an iterator - if (!PyIter_Check(iter)) { - PyErr_Format(PyExc_TypeError, "%R is not an iterator", Py_TYPE(iter)); - return PYGEN_ERROR; - } - - *presult = (Py_TYPE(iter)->tp_iternext)(iter); - if (*presult) return PYGEN_NEXT; - if (!PyErr_ExceptionMatches(PyExc_StopIteration)) return PYGEN_ERROR; - *presult = _fetch_stop_iteration_value(); - return PYGEN_RETURN; -} - -#endif - #if PY_VERSION_HEX < 0x030D0000 static int PyModule_Add(PyObject* module, const char* name, PyObject* value) { @@ -227,6 +162,9 @@ /// C-friendly representation of the csv dialect. Dialect dialect; + /// ID of the thread that has created the _Parser, to ensure it's not shared threads + unsigned long thread_id; + /// Limit for the field size long field_size_limit; @@ -351,6 +289,7 @@ static int Parser_clear(Parser* self) { Py_CLEAR(self->reader); Py_CLEAR(self->current_read); + Py_CLEAR(self->buffer_str); Py_CLEAR(self->record_so_far); return 0; } @@ -360,6 +299,8 @@ Parser* self = PyObject_GC_New(Parser, subtype); if (!self) return NULL; + self->thread_id = PyThread_get_thread_ident(); + // Zero-initialize all custom Parser fields. In case the initialization fails, // we need to ensure the deallocator doesn't stumble on garbage values. self->reader = NULL; @@ -755,9 +696,14 @@ PyErr_Format(PyExc_TypeError, "reader.read() returned %R, expected str", Py_TYPE(unicode)); FINISH_WITH(0); } + +#if PY_VERSION_HEX < 0x030C0000 + // PyUnicode_READY is a guaranteed no-op starting with 3.12, but before that other + // modules may produce strings using the deprecated path that requires preparation. if (PyUnicode_READY(unicode)) { FINISH_WITH(0); } +#endif Py_ssize_t len = PyUnicode_GET_LENGTH(unicode); assert(len >= 0); @@ -776,6 +722,12 @@ } static PyObject* Parser_next(Parser* self) { + // Prevent _Parser from being shared across threads + if (self->thread_id != PyThread_get_thread_ident()) { + PyErr_SetString(PyExc_RuntimeError, "aiocsv._parser.Parser instance must not be shared across threads"); + return NULL; + } + // Loop until a record has been successfully parsed or EOF has been hit PyObject* record = NULL; while (!record && (self->buffer_str || !self->eof)) { @@ -819,12 +771,6 @@ // *** Type Specification *** -// TODO: Once support 3.8 is dropped, the "Parser" function can be replaced by -// normal .tp_new and .tp_init members on the "_Parser" type. -// Starting with 3.9 it's possible to access modules state from the _Parser type -// with PyType_GetModuleState, but on 3.8 the module needs to be passed around directly -// from the fake constructor-function. - static PyMemberDef ParserMembers[] = { {"line_num", T_UINT, offsetof(Parser, line_num), READONLY, "Line number of the recently-returned row"}, @@ -930,6 +876,9 @@ #if PY_VERSION_HEX >= 0x030C0000 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, #endif +#if PY_VERSION_HEX >= 0x030D0000 + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, +#endif {0, NULL}, }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiocsv-1.4.0/pyproject.toml new/aiocsv-1.4.1/pyproject.toml --- old/aiocsv-1.4.0/pyproject.toml 2025-09-22 14:04:03.000000000 +0200 +++ new/aiocsv-1.4.1/pyproject.toml 2026-05-22 19:43:28.000000000 +0200 @@ -5,7 +5,7 @@ [project] name = "aiocsv" readme = "readme.md" -requires-python = ">=3.9" +requires-python = ">=3.10" dynamic = ["version"] authors = [ {name = "Mikołaj Kuranowski", email = "[email protected]"}, @@ -34,14 +34,9 @@ [tool.setuptools.dynamic] version = {attr = "aiocsv.__version__"} -[tool.black] +[tool.ruff] line-length = 99 -target-version = ['py39'] - -[tool.isort] -profile = "black" -line_length = 99 -py_version = 39 +target-version = "py310" [tool.pyright] typeCheckingMode = "strict" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiocsv-1.4.0/readme.md new/aiocsv-1.4.1/readme.md --- old/aiocsv-1.4.0/readme.md 2025-09-22 14:04:03.000000000 +0200 +++ new/aiocsv-1.4.1/readme.md 2026-05-22 19:43:28.000000000 +0200 @@ -5,7 +5,7 @@ ## Installation -`pip install aiocsv`. Python 3.8+ is required. +`pip install aiocsv`. Python 3.10+ is required. This module contains an extension written in C. Pre-build binaries may not be available for your configuration. You might need a C compiler @@ -292,9 +292,8 @@ Use [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python), [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) -(should be installed automatically alongside Python extension), -[black](https://marketplace.visualstudio.com/items?itemName=ms-python.black-formatter) and -[isort](https://marketplace.visualstudio.com/items?itemName=ms-python.isort) Python extensions. +(should be installed automatically alongside Python extension), and +[Ruff](https://marketplace.visualstudio.com/items?itemName=charliermarsh.ruff) extensions. You will need to install all dev dependencies from `requirements.dev.txt`, except for `pyright`. Recommended `.vscode/settings.json`: @@ -308,6 +307,7 @@ "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", "editor.formatOnSave": true, "editor.codeActionsOnSave": { "source.organizeImports": "always" @@ -332,7 +332,7 @@ "name": "Linux", "includePath": [ "${workspaceFolder}/**", - "/usr/include/python3.11" + "/usr/include/python3.14" ], "defines": [], "compilerPath": "/usr/bin/clang", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/aiocsv-1.4.0/requirements.dev.txt new/aiocsv-1.4.1/requirements.dev.txt --- old/aiocsv-1.4.0/requirements.dev.txt 2025-09-22 14:04:03.000000000 +0200 +++ new/aiocsv-1.4.1/requirements.dev.txt 2026-05-22 19:43:28.000000000 +0200 @@ -4,6 +4,5 @@ pytest-asyncio setuptools wheel -isort -black +ruff pyright
