Skip to content

Commit 17e7e6c

Browse files
committed
fix: restore Python 3.9/3.10 support broken in the v0.7.0 CI matrix
Two independent failures, both confirmed against the tests workflow on 246ec5c (Rust tests green, 3.9 and 3.10 red): * 3.9 - `flush_usage` used a bare PEP 604 `str | None` in its signature. Annotations are evaluated at definition time, and `type.__or__` only exists from 3.10, so importing the package raised `TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'` at __init__.py:175. Quote the annotation so it is never evaluated; `_Optional` is not imported until line 499. FA102 is removed from the ruff ignore list so this cannot regress silently again - it is a correctness guard for `requires-python = ">=3.9"`, not a style rule. * 3.10 - three packaging tests imported `tomllib` unconditionally, which only entered the stdlib in 3.11, so the 3.9/3.10 legs died at collection. Fall back to `tomli` the same way test_api_compat.py already does, and declare `tomli` for python_version < 3.11 so the tests actually run on those legs instead of erroring or skipping. Both were latent: earlier runs failed at the build or lint step and never reached them.
1 parent 246ec5c commit 17e7e6c

5 files changed

Lines changed: 25 additions & 6 deletions

File tree

pyproject.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ dev = [
5959
# A9-01: `tests.yml` invokes `pytest --timeout=120`. Without this plugin that
6060
# is an unrecognized argument and the whole job dies at collection.
6161
"pytest-timeout>=2.1.0",
62+
# Four packaging tests parse pyproject.toml with `tomllib`, which only
63+
# entered the stdlib in 3.11. Without this the 3.9/3.10 matrix legs die at
64+
# collection with ModuleNotFoundError rather than running the tests.
65+
"tomli>=2.0; python_version<'3.11'",
6266
"hypothesis>=6.0.4", # clears 1 Safety advisory; 6.0.4 still allows py3.6+
6367
"fastapi>=0.110.0",
6468
"uvicorn>=0.29.0",
@@ -195,8 +199,12 @@ docstring-code-format = true
195199
# E702: semicolons used intentionally for chained one-liners in plotting helpers.
196200
# E731: lambda assignments used for compact callback tables in a few helpers.
197201
# E741: single-letter variable names (l, I, O) are domain-conventional in QEC math.
198-
# S110, BLE001, FA102, C414, C401, RUF*, ISC004, UP045, B017, PLW1510, SIM118: style & optional-dep guards.
199-
ignore = ["E702", "E731", "E741", "S110", "BLE001", "FA102", "FA100", "C414", "C401", "RUF012", "RUF023", "RUF034", "RUF046", "RUF059", "RUF100", "ISC004", "UP045", "B017", "PLW1510", "SIM118"]
202+
# S110, BLE001, C414, C401, RUF*, ISC004, UP045, B017, PLW1510, SIM118: style & optional-dep guards.
203+
#
204+
# FA102 is deliberately NOT ignored: `requires-python = ">=3.9"`, and a bare
205+
# PEP 604 `X | Y` in a signature is evaluated at import time, so on 3.9 it
206+
# raises TypeError and makes the whole package unimportable. Keep it enforcing.
207+
ignore = ["E702", "E731", "E741", "S110", "BLE001", "FA100", "C414", "C401", "RUF012", "RUF023", "RUF034", "RUF046", "RUF059", "RUF100", "ISC004", "UP045", "B017", "PLW1510", "SIM118"]
200208

201209
[tool.ruff.lint.per-file-ignores]
202210
# __init__: late imports (E402) are intentional (runtime optional deps).

python/qector_decoder_v3/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ def get_accumulated_shots() -> int:
172172
return 0
173173

174174

175-
def flush_usage(customer_id: str | None = None, api_key: str | None = None) -> dict:
175+
def flush_usage(customer_id: "str | None" = None, api_key: "str | None" = None) -> dict:
176176
"""Flush accumulated decode shots to the Stripe Billing Meter Events API.
177177
178178
``customer_id`` falls back to ``QECTOR_STRIPE_CUSTOMER_ID`` and ``api_key``

python/tests/test_license_included.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010

1111
import os
1212

13-
import tomllib
13+
try:
14+
import tomllib
15+
except ModuleNotFoundError: # Python < 3.11 - tomllib entered the stdlib in 3.11
16+
import tomli as tomllib
1417

1518

1619
def _repo_root():

python/tests/test_optional_extras.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@
99
import os
1010

1111
import pytest
12-
import tomllib
12+
13+
try:
14+
import tomllib
15+
except ModuleNotFoundError: # Python < 3.11 - tomllib entered the stdlib in 3.11
16+
import tomli as tomllib
1317

1418

1519
def _repo_root():

python/tests/test_version_consistency.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
import os
1515

1616
import qector_decoder_v3
17-
import tomllib
17+
18+
try:
19+
import tomllib
20+
except ModuleNotFoundError: # Python < 3.11 - tomllib entered the stdlib in 3.11
21+
import tomli as tomllib
1822

1923

2024
def _repo_root():

0 commit comments

Comments
 (0)