diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 62fba68c..a9a47a5c 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -16,7 +16,7 @@ jobs: fail-fast: false matrix: os: ["ubuntu-latest", "windows-latest", "macos-latest"] - python: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python: ["3.10", "3.11", "3.12", "3.13", "3.14"] name: "Python ${{ matrix.python }} / ${{ matrix.os }}" runs-on: ${{ matrix.os }} diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml index ae72354a..d01697f5 100644 --- a/.github/workflows/typecheck.yml +++ b/.github/workflows/typecheck.yml @@ -19,7 +19,7 @@ jobs: - uses: actions/setup-python@v6 with: - python-version: 3.9 + python-version: "3.10" - run: | python3 -m pip install -U pip diff --git a/CHANGELOG.md b/CHANGELOG.md index fb27fd61..e6ba7b85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Changed + +- **Python Support**: Dropped Python 3.9 support, added Python 3.14 support. Now requires Python >=3.10, <3.15. + ## [0.2.0] - 2025-12-26 ### Added diff --git a/graphqomb/command.py b/graphqomb/command.py index 56ae7c90..f3603d14 100644 --- a/graphqomb/command.py +++ b/graphqomb/command.py @@ -14,8 +14,7 @@ from __future__ import annotations import dataclasses -import sys -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING if TYPE_CHECKING: from graphqomb.common import MeasBasis @@ -117,7 +116,4 @@ def __str__(self) -> str: return "TICK" -if sys.version_info >= (3, 10): - Command = N | E | M | X | Z | TICK -else: - Command = Union[N, E, M, X, Z, TICK] +Command = N | E | M | X | Z | TICK diff --git a/graphqomb/feedforward.py b/graphqomb/feedforward.py index ce4ccd65..e1f558ef 100644 --- a/graphqomb/feedforward.py +++ b/graphqomb/feedforward.py @@ -11,22 +11,16 @@ from __future__ import annotations -import sys from collections.abc import Iterable, Mapping from collections.abc import Set as AbstractSet from graphlib import TopologicalSorter -from typing import Any +from typing import Any, TypeGuard import typing_extensions from graphqomb.common import Axis, Plane, determine_pauli_axis from graphqomb.graphstate import BaseGraphState, odd_neighbors -if sys.version_info >= (3, 10): - from typing import TypeGuard -else: - from typing_extensions import TypeGuard - def _is_flow(flowlike: Mapping[int, Any]) -> TypeGuard[Mapping[int, int]]: r"""Check if the flowlike object is a flow. diff --git a/graphqomb/gates.py b/graphqomb/gates.py index db72c85c..9dc6b12a 100644 --- a/graphqomb/gates.py +++ b/graphqomb/gates.py @@ -31,10 +31,9 @@ from __future__ import annotations import math -import sys from abc import ABC, abstractmethod from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeAlias import numpy as np @@ -224,7 +223,7 @@ def matrix(self) -> NDArray[np.complex128]: def count_ones_in_binary(array: NDArray[np.int64]) -> NDArray[np.int64]: def count_ones_single(x: np.int64) -> int: - return bin(int(x)).count("1") + return int(x).bit_count() count_ones = np.vectorize(count_ones_single) return np.asarray(count_ones(array), dtype=np.int64) @@ -234,18 +233,8 @@ def count_ones_single(x: np.int64) -> int: return np.diag(np.exp(-1j * self.angle / 2 * z_sign)) -if sys.version_info >= (3, 10): - from typing import TypeAlias - - UnitGate: TypeAlias = J | CZ | PhaseGadget - """Unit gate type""" -else: - from typing import Union - - from typing_extensions import TypeAlias - - UnitGate: TypeAlias = Union[J, CZ, PhaseGadget] - """Unit gate type""" +UnitGate: TypeAlias = J | CZ | PhaseGadget +"""Unit gate type""" @dataclass(frozen=True) diff --git a/graphqomb/pattern.py b/graphqomb/pattern.py index cf98f766..f0a8d531 100644 --- a/graphqomb/pattern.py +++ b/graphqomb/pattern.py @@ -18,8 +18,7 @@ from graphqomb.command import TICK, Command, E, M, N, X, Z if TYPE_CHECKING: - from collections.abc import Iterator - from typing import Callable + from collections.abc import Callable, Iterator from graphqomb.pauli_frame import PauliFrame diff --git a/pyproject.toml b/pyproject.toml index f46be8ac..06a71eee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ name = "graphqomb" version = "0.2.0" description = "A modular Graph State qompiler for measurement-based quantum computing." readme = "README.md" -requires-python = ">=3.9, <3.14" +requires-python = ">=3.10, <3.15" license = {text = "MIT"} authors = [ {name = "Masato Fukushima", email = "masa1063fuk@gmail.com"}, @@ -32,11 +32,11 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Scientific/Engineering :: Physics", "Topic :: Scientific/Engineering :: Quantum Computing", "Topic :: Software Development :: Libraries :: Python Modules", @@ -58,7 +58,7 @@ dev = { file = ["requirements-dev.txt"] } doc = { file = ["docs/requirements.txt"] } [tool.ruff] -target-version = "py39" +target-version = "py310" line-length = 120 [tool.ruff.lint] diff --git a/tests/test_circuit.py b/tests/test_circuit.py index 87399628..b5252153 100644 --- a/tests/test_circuit.py +++ b/tests/test_circuit.py @@ -191,7 +191,7 @@ def test_circuit_instructions_matches_manual_expansion() -> None: assert len(instructions) == len(expected_instructions) # Compare each instruction - for inst, expected in zip(instructions, expected_instructions): + for inst, expected in zip(instructions, expected_instructions, strict=False): assert type(inst) is type(expected) if isinstance(inst, J) and isinstance(expected, J): assert inst.qubit == expected.qubit @@ -225,7 +225,7 @@ def test_circuit_instructions_returns_copy() -> None: assert macro1 is not macro2 # But with same contents assert len(macro1) == len(macro2) - for g1, g2 in zip(macro1, macro2): + for g1, g2 in zip(macro1, macro2, strict=False): assert type(g1) is type(g2) diff --git a/tests/test_euler.py b/tests/test_euler.py index fb361499..d5ced1a9 100644 --- a/tests/test_euler.py +++ b/tests/test_euler.py @@ -18,7 +18,7 @@ from graphqomb.matrix import is_unitary if TYPE_CHECKING: - from typing import Callable + from collections.abc import Callable @pytest.fixture