From c223d21edb1643d89257c2d8a5450b952554db75 Mon Sep 17 00:00:00 2001 From: Ivan Carvalho <8753214+IvanIsCoding@users.noreply.github.com> Date: Thu, 3 Oct 2024 21:54:37 -0400 Subject: [PATCH] Remove support for Python 3.8 (#1290) * Remove support for Python 3.8 (EOL) * Add release note * Update black to support newer Python syntaxes * Update mypy as well * More fixes * Bump ruff as well * Fix lint finds --- .github/workflows/docs_dev.yml | 2 +- .github/workflows/docs_release.yml | 2 +- .github/workflows/main.yml | 16 +++++++--------- .github/workflows/wheels.yml | 4 ++-- .mergify.yml | 3 --- Cargo.toml | 2 +- constraints.txt | 1 - noxfile.py | 10 +++++----- pyproject.toml | 8 ++++---- .../notes/py38-eol-6443a548b6c727cc.yaml | 6 ++++++ rustworkx/__init__.pyi | 3 ++- rustworkx/generators/__init__.pyi | 3 ++- rustworkx/rustworkx.pyi | 10 ++++++---- rustworkx/visualization/matplotlib.pyi | 18 ++++++++++++++---- setup.py | 5 ++--- tests/graph/test_max_weight_matching.py | 8 ++++---- tests/graph/test_planar.py | 4 ++-- tests/test_graphml.py | 2 +- tests/test_token_swapper.py | 2 +- tests/visualization/test_mpl.py | 2 +- tox.ini | 6 +++--- 21 files changed, 65 insertions(+), 52 deletions(-) create mode 100644 releasenotes/notes/py38-eol-6443a548b6c727cc.yaml diff --git a/.github/workflows/docs_dev.yml b/.github/workflows/docs_dev.yml index a253cc46b..1d69e2e37 100644 --- a/.github/workflows/docs_dev.yml +++ b/.github/workflows/docs_dev.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.8' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/docs_release.yml b/.github/workflows/docs_release.yml index 843ed6743..013e4a6c7 100644 --- a/.github/workflows/docs_release.yml +++ b/.github/workflows/docs_release.yml @@ -19,7 +19,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.8' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d1797fe74..907c964e1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,8 +25,8 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: 3.8 - - run: pip install -U ruff==0.4.1 black~=22.0 + python-version: "3.10" + - run: pip install -U ruff==0.6.8 black~=24.8 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt @@ -58,7 +58,7 @@ jobs: strategy: matrix: rust: [stable] - python-version: [3.8, 3.9, "3.10", "3.11", "3.12"] + python-version: [3.9, "3.10", "3.11", "3.12"] platform: [ { os: "macOS-13", python-architecture: "x64", rust-target: "x86_64-apple-darwin" }, { os: "macOS-14", python-architecture: "arm64", rust-target: "aarch64-apple-darwin" }, @@ -68,7 +68,7 @@ jobs: include: # Test minimal supported Rust version - rust: 1.70.0 - python-version: 3.8 + python-version: "3.10" platform: { os: "ubuntu-latest", python-architecture: "x64", rust-target: "x86_64-unknown-linux-gnu" } msrv: "MSRV" # Test future versions of Rust and Python @@ -76,10 +76,8 @@ jobs: python-version: "3.13-dev" platform: { os: "ubuntu-latest", python-architecture: "x64", rust-target: "x86_64-unknown-linux-gnu" } msrv: "Beta" - # Exclude python 3.8 and 3.9 on arm64 until actions/setup-python#808 is resolved + # Exclude python 3.9 on arm64 until actions/setup-python#808 is resolved exclude: - - platform: {os: "macOS-14", python-architecture: "arm64", rust-target: "aarch64-apple-darwin" } - python-version: 3.8 - platform: {os: "macOS-14", python-architecture: "arm64", rust-target: "aarch64-apple-darwin" } python-version: 3.9 steps: @@ -109,7 +107,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.8, 3.9, "3.10", "3.11"] + python-version: [3.9, "3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} @@ -179,7 +177,7 @@ jobs: - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: - python-version: 3.8 + python-version: "3.10" - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install binary deps diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b14256497..5b1a9e463 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -149,8 +149,8 @@ jobs: python -m cibuildwheel --output-dir wheelhouse env: CIBW_ARCHS_LINUX: aarch64 - CIBW_SKIP: cp36-* cp37-* *many* - CIBW_TEST_SKIP: cp37-* cp38-* cp39-* cp310-* cp311-* cp312-* *many* + CIBW_SKIP: cp36-* cp37-* cp38-* *many* + CIBW_TEST_SKIP: cp39-* cp310-* cp311-* cp312-* *many* - uses: actions/upload-artifact@v4 with: path: ./wheelhouse/*.whl diff --git a/.mergify.yml b/.mergify.yml index 254ce2477..3438adc73 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -1,9 +1,6 @@ queue_rules: - name: automerge conditions: - - check-success=python3.8-x64 windows-latest - - check-success=python3.8-x64 ubuntu-latest - - check-success=python3.8-x64 macOS-latest - check-success=python3.9-x64 windows-latest - check-success=python3.9-x64 ubuntu-latest - check-success=python3.9-x64 macOS-latest diff --git a/Cargo.toml b/Cargo.toml index 6c75c894d..667d17de7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ rustworkx-core = { path = "rustworkx-core", version = "=0.16.0" } [dependencies.pyo3] version = "0.21.2" -features = ["abi3-py38", "extension-module", "hashbrown", "num-bigint", "num-complex", "indexmap"] +features = ["abi3-py39", "extension-module", "hashbrown", "num-bigint", "num-complex", "indexmap"] [dependencies.sprs] version = "^0.11" diff --git a/constraints.txt b/constraints.txt index 623a9cc4f..4927e21b0 100644 --- a/constraints.txt +++ b/constraints.txt @@ -1,4 +1,3 @@ decorator==4.4.2 -importlib-metadata==4.13.0;python_version<'3.8' pillow<10.0.0;python_version<'3.13' lxml==5.1.1 diff --git a/noxfile.py b/noxfile.py index 4a2b75713..1b6221254 100644 --- a/noxfile.py +++ b/noxfile.py @@ -12,19 +12,19 @@ ] lint_deps = [ - "black~=22.0", - "ruff~=0.1", + "black~=24.8", + "ruff~=0.6", "setuptools-rust", ] stubs_deps = [ - "mypy==1.8.0", + "mypy==1.11.2", "typing-extensions", ] def install_rustworkx(session): session.install(*deps) - session.install(".[all]", "-c", "constraints.txt") + session.install(".", "-c", "constraints.txt") # We define a common base such that -e test triggers a test with the current # Python version of the interpreter and -e test_with_version launches @@ -38,7 +38,7 @@ def base_test(session): def test(session): base_test(session) -@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12"]) +@nox.session(python=["3.9", "3.10", "3.11", "3.12"]) def test_with_version(session): base_test(session) diff --git a/pyproject.toml b/pyproject.toml index a7da3f16c..2a752ec1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 100 -target-version = ['py38', 'py39', 'py310', 'py311'] +target-version = ['py39', 'py310', 'py311', 'py312'] [tool.ruff] line-length = 105 # more lenient than black due to long function signatures @@ -16,7 +16,7 @@ lint.select = [ "PYI", # flake8-pyi "Q", # flake8-quotes ] -target-version = "py38" +target-version = "py39" extend-exclude = ["doc"] [tool.ruff.lint.per-file-ignores] @@ -26,11 +26,11 @@ extend-exclude = ["doc"] [tool.cibuildwheel] manylinux-x86_64-image = "manylinux2014" manylinux-i686-image = "manylinux2014" -skip = "pp* cp36-* cp37-* *win32 *musllinux*i686" +skip = "pp* cp36-* cp37-* cp38-* *win32 *musllinux*i686" test-requires = "networkx" test-command = "python -m unittest discover {project}/tests" before-build = "pip install -U setuptools-rust" -test-skip = "cp38-*musllinux* *linux_s390x *ppc64le" +test-skip = "*linux_s390x *ppc64le" [tool.cibuildwheel.linux] before-all = "yum install -y wget && {package}/tools/install_rust.sh" diff --git a/releasenotes/notes/py38-eol-6443a548b6c727cc.yaml b/releasenotes/notes/py38-eol-6443a548b6c727cc.yaml new file mode 100644 index 000000000..d4e736808 --- /dev/null +++ b/releasenotes/notes/py38-eol-6443a548b6c727cc.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + The minimum supported Python version for using rustworkx has been raised to Python 3.9. + Python 3.8 has reached it's end-of-life and will no longer be supported. To use rustworkx + you will need to ensure you are using Python >=3.9. \ No newline at end of file diff --git a/rustworkx/__init__.pyi b/rustworkx/__init__.pyi index 754c02f60..63f5f4be4 100644 --- a/rustworkx/__init__.pyi +++ b/rustworkx/__init__.pyi @@ -11,7 +11,8 @@ import numpy as np -from typing import Generic, TypeVar, Any, Callable, Iterator, overload, Sequence +from typing import Generic, TypeVar, Any, Callable, overload +from collections.abc import Iterator, Sequence # Re-Exports of rust native functions in rustworkx.rustworkx # To workaround limitations in mypy around re-exporting objects from the inner diff --git a/rustworkx/generators/__init__.pyi b/rustworkx/generators/__init__.pyi index 99946bed8..440db3940 100644 --- a/rustworkx/generators/__init__.pyi +++ b/rustworkx/generators/__init__.pyi @@ -12,7 +12,8 @@ from rustworkx import PyGraph from rustworkx import PyDiGraph -from typing import Sequence, Any +from typing import Any +from collections.abc import Sequence def cycle_graph( num_nodes: int | None = ..., weights: Sequence[Any] | None = ..., multigraph: bool = ... diff --git a/rustworkx/rustworkx.pyi b/rustworkx/rustworkx.pyi index 474472cf0..d0be41c5a 100644 --- a/rustworkx/rustworkx.pyi +++ b/rustworkx/rustworkx.pyi @@ -13,17 +13,19 @@ from .visit import BFSVisitor, DFSVisitor, DijkstraVisitor from typing import ( TypeVar, Callable, - Iterable, - Iterator, final, - Sequence, Any, Generic, + overload, +) +from collections.abc import ( + Iterable, + Iterator, + Sequence, ItemsView, KeysView, ValuesView, Mapping, - overload, Hashable, ) from abc import ABC diff --git a/rustworkx/visualization/matplotlib.pyi b/rustworkx/visualization/matplotlib.pyi index 3c5625d7f..3f8da1fd1 100644 --- a/rustworkx/visualization/matplotlib.pyi +++ b/rustworkx/visualization/matplotlib.pyi @@ -26,18 +26,28 @@ class _DrawKwargs(typing.TypedDict, total=False): node_list: list[int] edge_list: list[int] node_size: int | list[int] - node_color: str | tuple[float, float, float] | tuple[float, float, float, float] | list[ + node_color: ( str - ] | list[tuple[float, float, float]] | list[tuple[float, float, float, float]] + | tuple[float, float, float] + | tuple[float, float, float, float] + | list[str] + | list[tuple[float, float, float]] + | list[tuple[float, float, float, float]] + ) node_shape: str alpha: float cmap: Colormap vmin: float vmax: float linewidths: float | list[float] - edge_color: str | tuple[float, float, float] | tuple[float, float, float, float] | list[ + edge_color: ( str - ] | list[tuple[float, float, float]] | list[tuple[float, float, float, float]] + | tuple[float, float, float] + | tuple[float, float, float, float] + | list[str] + | list[tuple[float, float, float]] + | list[tuple[float, float, float, float]] + ) edge_cmap: Colormap edge_vmin: float edge_vmax: float diff --git a/setup.py b/setup.py index 12485f05a..16f9dcdec 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ def readme(): PKG_INSTALL_REQUIRES = ["numpy>=1.16.0,<3"] RUST_EXTENSIONS = [RustExtension("rustworkx.rustworkx", "Cargo.toml", binding=Binding.PyO3, debug=rustworkx_debug)] -RUST_OPTS ={"bdist_wheel": {"py_limited_api": "cp38"}} +RUST_OPTS ={"bdist_wheel": {"py_limited_api": "cp39"}} retworkx_readme_compat = """# retworkx @@ -66,7 +66,6 @@ def readme(): "Intended Audience :: Science/Research", "Programming Language :: Rust", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -86,7 +85,7 @@ def readme(): include_package_data=True, packages=PKG_PACKAGES, zip_safe=False, - python_requires=">=3.8", + python_requires=">=3.9", install_requires=PKG_INSTALL_REQUIRES, extras_require={ "mpl": mpl_extras, diff --git a/tests/graph/test_max_weight_matching.py b/tests/graph/test_max_weight_matching.py index 1b07a2eeb..06fbbde5e 100644 --- a/tests/graph/test_max_weight_matching.py +++ b/tests/graph/test_max_weight_matching.py @@ -27,7 +27,7 @@ def match_dict_to_set(match): class TestMaxWeightMatching(unittest.TestCase): def compare_match_sets(self, rx_match, expected_match): - for (u, v) in rx_match: + for u, v in rx_match: if (u, v) not in expected_match and (v, u) not in expected_match: self.fail( f"Element {(u, v)} and it's reverse {(v, u)} not found in " @@ -49,7 +49,7 @@ def get_nx_weight(edge): return weight["weight"] not_match = False - for (u, v) in rx_matches: + for u, v in rx_matches: if (u, v) not in nx_matches: if (v, u) not in nx_matches: not_match = True @@ -57,11 +57,11 @@ def get_nx_weight(edge): if not_match: self.assertTrue( rustworkx.is_matching(rx_graph, rx_matches), - "%s is not a valid matching" % rx_matches, + f"{rx_matches} is not a valid matching", ) self.assertTrue( rustworkx.is_maximal_matching(rx_graph, rx_matches), - "%s is not a maximal matching" % rx_matches, + f"{rx_matches} is not a maximal matching", ) self.assertEqual( sum(map(get_rx_weight, rx_matches)), diff --git a/tests/graph/test_planar.py b/tests/graph/test_planar.py index 92750ad0f..2cf68b7fa 100644 --- a/tests/graph/test_planar.py +++ b/tests/graph/test_planar.py @@ -266,7 +266,7 @@ def test_generalized_petersen_graph_planar_instances(self): iter((n, 1) for n in range(3, 17)), iter((n, 2) for n in range(6, 17, 2)), ) - for (n, k) in planars: + for n, k in planars: with self.subTest(n=n, k=k): graph = rx.generators.generalized_petersen_graph(n=n, k=k) self.assertTrue(rx.is_planar(graph)) @@ -277,7 +277,7 @@ def test_generalized_petersen_graph_non_planar_instances(self): iter((n, 2) for n in range(5, 17, 2)), iter((n, k) for k in range(3, 9) for n in range(2 * k + 1, 17)), ) - for (n, k) in no_planars: + for n, k in no_planars: with self.subTest(n=n, k=k): graph = rx.generators.generalized_petersen_graph(n=n, k=k) self.assertFalse(rx.is_planar(graph)) diff --git a/tests/test_graphml.py b/tests/test_graphml.py index 5556e12bf..fee85da4a 100644 --- a/tests/test_graphml.py +++ b/tests/test_graphml.py @@ -44,7 +44,7 @@ def assertGraphEqual(self, graph, nodes, edges, directed=True, attrs={}): for node_a, node_b in zip(graph.nodes(), nodes): self.assertDictPayloadEqual(node_a, node_b) - for ((s, t, data), edge) in zip(graph.weighted_edge_list(), edges): + for (s, t, data), edge in zip(graph.weighted_edge_list(), edges): self.assertEqual((graph[s]["id"], graph[t]["id"]), (edge[0], edge[1])) self.assertDictPayloadEqual(data, edge[2]) diff --git a/tests/test_token_swapper.py b/tests/test_token_swapper.py index aafc6e6ff..2fa9b22de 100644 --- a/tests/test_token_swapper.py +++ b/tests/test_token_swapper.py @@ -21,7 +21,7 @@ def swap_permutation( mapping, swaps, ) -> None: - for (sw1, sw2) in list(swaps): + for sw1, sw2 in list(swaps): val1 = mapping.pop(sw1, None) val2 = mapping.pop(sw2, None) diff --git a/tests/visualization/test_mpl.py b/tests/visualization/test_mpl.py index 2208b4f3f..705a5b80f 100644 --- a/tests/visualization/test_mpl.py +++ b/tests/visualization/test_mpl.py @@ -121,7 +121,7 @@ def test_draw_edges_min_source_target_margins(self): min_source_margin=100, min_target_margin=100, ) - _save_images(fig, "test_node_shape_%s.png" % node_shape) + _save_images(fig, f"test_node_shape_{node_shape}.png") def test_alpha_iter(self): graph = rustworkx.generators.grid_graph(4, 6) diff --git a/tox.ini b/tox.ini index 63e661d99..712139c01 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 4.4.0 -envlist = py37, py38, py39, py310, py311, lint +envlist = py39, py310, py311, lint isolated_build = true [testenv] @@ -33,7 +33,7 @@ commands = basepython = python3 skip_install = true deps = - black~=22.0 + black~=24.8 ruff allowlist_externals=cargo commands = @@ -75,7 +75,7 @@ commands = basepython = python3 skip_install = true deps = - black~=22.0 + black~=24.8 commands = black {posargs} '../rustworkx' '../tests' '../retworkx' python -c "print('\nrustworkx no longer supports tox. Please run the equivalent comand with nox:\n\tnox -e black\n')"