Skip to content

Conversation

@igorcoding
Copy link
Owner

  • Add PyUnicodeWriter compatibility macros for Python 3.14+ (Python 3.14 introduced public PyUnicodeWriter API, deprecating private _PyUnicodeWriter)
  • Add PyHASH_MULTIPLIER compatibility macro for Python 3.13+ (Python 3.13 introduced public PyHASH_MULTIPLIER constant)
  • Update ttuple_repr() and ttuple_hash() to use new compatibility macros
  • Simplify trashcan macros (always use Py_TRASHCAN_BEGIN/END for Python 3.8+)
  • Remove obsolete Python 2.x and <3.7 backports from datetime handling
  • Remove python.pxd (no longer needed, use standard cpython.datetime)
  • Update datetime.pyx to use cpython.datetime's timezone_new and datetime_from_timestamp
  • Remove dateutil dependency from tests (datetime.fromisoformat available since 3.7)

@igorcoding igorcoding force-pushed the python314-support branch 5 times, most recently from d7c69ff to 649748b Compare January 18, 2026 20:41
Python 3.14 compatibility:
- Add PyUnicodeWriter compatibility macros for Python 3.14+
  (Python 3.14 introduced public PyUnicodeWriter API, deprecating private _PyUnicodeWriter)
- Add PyHASH_MULTIPLIER compatibility macro for Python 3.13+
  (Python 3.13 introduced public PyHASH_MULTIPLIER constant)
- Update ttuple_repr() and ttuple_hash() to use new compatibility macros

Free-threaded Python support:
- Add `freethreading_compatible=True` Cython directive to protocol.pyx
- Disable C freelist in tupleobj.c when Py_GIL_DISABLED is defined
  (global static arrays are not thread-safe without the GIL)

Code cleanup (Python 3.9+ minimum):
- Simplify trashcan macros (always use Py_TRASHCAN_BEGIN/END for Python 3.9+)
- Remove obsolete Python 2.x and <3.7 backports from datetime handling
- Remove python.pxd (no longer needed, use standard cpython.datetime)
- Update datetime.pyx to use cpython.datetime's timezone_new and datetime_from_timestamp
- Remove dateutil dependency from tests (datetime.fromisoformat available since 3.7)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Python 3.14 support and removes compatibility code for Python versions < 3.8. The changes modernize the codebase by:

  • Upgrading Cython from 3.0.11 to 3.2.4
  • Adding compatibility macros for Python 3.13+ (PyHASH_MULTIPLIER) and Python 3.14+ (PyUnicodeWriter API)
  • Adding free-threaded (no-GIL) build support for Python 3.13+
  • Removing obsolete Python 2.x and <3.7 compatibility code
  • Removing the dateutil test dependency (using datetime.fromisoformat instead)
  • Updating build tooling to use uv

Changes:

  • Add Python 3.14 compatibility macros for PyUnicodeWriter and PyHASH_MULTIPLIER in C code
  • Disable C freelist in free-threaded builds to ensure thread safety
  • Remove python.pxd and use standard cpython.datetime functions
  • Update test code to use datetime.fromisoformat instead of dateutil
  • Modernize build configuration (Cython 3.2.4, setuptools>=77, uv tooling)

Reviewed changes

Copilot reviewed 23 out of 24 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
asynctnt/iproto/tupleobj/tupleobj.h Added compatibility macros for Python 3.13+ (PyHASH_MULTIPLIER) and 3.14+ (PyUnicodeWriter API)
asynctnt/iproto/tupleobj/tupleobj.c Updated to use new compatibility macros and disabled freelist for free-threaded builds
asynctnt/iproto/python.pxd Removed obsolete Python 2.x and <3.7 compatibility code
asynctnt/iproto/ext/datetime.pyx Updated to use cpython.datetime's timezone_new and datetime_from_timestamp
asynctnt/iproto/protocol.pyx Added freethreading_compatible directive
asynctnt/iproto/protocol.pxd Removed python.pxd include
tests/test_mp_ext.py Removed dateutil dependency, using datetime.fromisoformat instead
tests/*.py Fixed string concatenation style (removing implicit concatenation)
tests/_testbase.py Added length assertion to assertResponseEqual and noqa comment for print
pyproject.toml Updated Python version support (3.9-3.14), Cython version, removed black/isort, expanded ruff config
setup.py Updated Cython version to 3.2.4
.github/workflows/actions.yaml Updated CI matrix for Python 3.9-3.14, PyPy 3.11, and modernized to use uv
Makefile Updated to use uv commands
README.md Updated minimum Python version requirement to 3.9
CHANGELOG.md Added v2.5.0 release notes
bench/benchmark.py Updated to use uvloop.run and added noqa comments for prints
asynctnt/init.py Version bump to 2.5.0
asynctnt/connection.py Fixed string concatenation style
.gitignore Added uv-related entries

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
'Programming Language :: Python :: Implementation :: CPython',
"Intended Audience :: Developers",
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "License :: OSI Approved :: Apache Software License" classifier was removed from the classifiers list. This classifier is important for PyPI users to filter packages by license type. Consider restoring this classifier to maintain compatibility with PyPI's license filtering.

Copilot uses AI. Check for mistakes.
./scripts/run_until_success.sh uv run coverage html
build-wheels:
name: Build wheels on ${{ matrix.os }}
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build-wheels job is now triggered on every push, whereas previously it was restricted to tag pushes only (via the if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') condition). This means wheel builds will run unnecessarily on every commit, consuming CI resources. Consider restoring the condition to only build wheels when pushing tags.

Suggested change
name: Build wheels on ${{ matrix.os }}
name: Build wheels on ${{ matrix.os }}
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')

Copilot uses AI. Check for mistakes.
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.14' && matrix.tarantool == '3'
env:
ASYNCTNT_DEBUG: "1"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}"
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a syntax error in the GITHUB_TOKEN environment variable - it has an extra double quote at the end. This will cause the token to include a literal quote character, which could lead to authentication issues. Remove the trailing double quote.

Suggested change
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Copilot uses AI. Check for mistakes.
Comment on lines +66 to 69
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.14' && matrix.tarantool == '3'
env:
ASYNCTNT_DEBUG: "1"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}"
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The coverage test condition has changed from Python 3.12 to Python 3.14. Since Python 3.14 is newly added and might not be fully stable yet (especially the free-threaded build), consider whether coverage should still be tested on a more stable Python version like 3.12 or 3.13. This ensures consistent coverage reporting even if 3.14 has compatibility issues.

Suggested change
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.14' && matrix.tarantool == '3'
env:
ASYNCTNT_DEBUG: "1"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}"
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.tarantool == '3'
env:
ASYNCTNT_DEBUG: "1"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Copilot uses AI. Check for mistakes.
loop.run_until_complete(
async_bench(

async def main(name=name, conn_creator=conn_creator):
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inner async function definition shadows the outer main function name. While this works due to scoping, it's confusing to have two different functions with the same name in close proximity. Consider renaming the inner async function to something like bench_main or run_benchmark to avoid confusion.

Copilot uses AI. Check for mistakes.
Comment on lines +109 to +167
# Аналогично black, двойные кавычки
quote-style = "double"

# Аналогично black, пробелы вместо табов
indent-style = "space"

# Аналогично black, уважаем trailing commas
skip-magic-trailing-comma = false

# Аналогично black, автоматически определяем подходящее окончание строки.
line-ending = "auto"

[tool.ruff.lint]
# Список кодов или префиксов правил, которые следует считать исправляемыми. (https://docs.astral.sh/ruff/settings/#fixable)
# По умолчанию все правила считаются исправляемыми.
fixable = ["I", "RUF022", "RUF023", "F401"]
preview = true

select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"C", # flake8-comprehensions
"B", # flake8-bugbear
"T20", # flake8-print
]
lint.ignore = [
"E501", # line too long, handled by black
"B008", # do not perform function calls in argument defaults
"C901", # too complex
ignore = [
"E501", # line too long, handled by black
"B008", # do not perform function calls in argument defaults
"C901", # too complex
]

extend-exclude = [
"app/store/migrations",
[tool.ruff.lint.isort]
# Позволяет использовать as в комбинации с группировкой (https://docs.astral.sh/ruff/settings/#isort-combine-as-imports)
#from package import (
# func1 as foo,
# func2 as boo,
#)
combine-as-imports = true

# Воспринимать следующие пакеты в качестве stdlib (https://docs.astral.sh/ruff/settings/#isort-extra-standard-library)
extra-standard-library = ["typing_extensions"]

section-order = [
"future",
"standard-library",
"third-party",
"first-party",
"local-folder"
]

# Не добавлять пустую строку перед данными секциям (https://docs.astral.sh/ruff/settings/#isort-no-lines-before)
no-lines-before = []

[tool.ruff.lint.pep8-naming]
# если навесить данные декораторы, то можно использовать cls (https://docs.astral.sh/ruff/settings/#pep8-naming-classmethod-decorators)
# в качестве первого аргумента.
classmethod-decorators = ["cached_classproperty", "classproperty"]
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments in the ruff configuration section are in Russian (Cyrillic). While this doesn't affect functionality, it may be better to use English comments for international collaboration and consistency with the rest of the codebase, which uses English comments.

Copilot uses AI. Check for mistakes.
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel coveralls
run: uv sync --extra test
Copy link

Copilot AI Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub Actions workflow uses 'uv sync --extra test' but the Makefile uses 'uv pip install -e' commands. These are different approaches - 'uv sync' expects a uv.lock file (which is in .gitignore), while 'uv pip install' works like pip. This inconsistency could lead to different dependency resolution between CI and local development. Consider either adding uv.lock to version control if you want reproducible builds, or use 'uv pip install' consistently in both places.

Suggested change
run: uv sync --extra test
run: uv pip install -e '.[test]'

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants