diff --git a/.github/py-shiny/setup/action.yaml b/.github/py-shiny/setup/action.yaml index dfa398f9f..0c50c616e 100644 --- a/.github/py-shiny/setup/action.yaml +++ b/.github/py-shiny/setup/action.yaml @@ -4,7 +4,7 @@ inputs: python-version: description: 'Python version to use' required: false - default: "3.12" + default: "3.13" runs: using: "composite" steps: @@ -39,12 +39,6 @@ runs: run: | make ci-install-wheel - - name: Install backports.tarfile - if: ${{ startsWith(inputs.python-version, '3.8') }} - shell: bash - run: | - uv pip install backports.tarfile - - name: Pip list shell: bash run: | diff --git a/.github/workflows/build-docs.yaml b/.github/workflows/build-docs.yaml index 818fe47e1..8d1d3c037 100644 --- a/.github/workflows/build-docs.yaml +++ b/.github/workflows/build-docs.yaml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.12"] + python-version: ["3.13"] fail-fast: false steps: diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml index ad355f70b..8f7621436 100644 --- a/.github/workflows/pytest.yaml +++ b/.github/workflows/pytest.yaml @@ -17,7 +17,7 @@ jobs: strategy: matrix: # "3.10" must be a string; otherwise it is interpreted as 3.1. - python-version: ["3.12", "3.11", "3.10", "3.9"] + python-version: ["3.13", "3.12", "3.11", "3.10", "3.9"] os: [ubuntu-latest, windows-latest, macOS-latest] exclude: - python-version: ${{ github.event.pull_request.draft && '3.11' }} @@ -73,7 +73,7 @@ jobs: with: fetch-depth: 0 - name: "Set up Python 3.10" - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.10" - name: Install dependencies @@ -107,7 +107,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.12", "3.11", "3.10", "3.9"] + python-version: ["3.13", "3.12", "3.11", "3.10", "3.9"] browser: ["chromium", "firefox", "webkit"] exclude: - python-version: ${{ github.event.pull_request.draft && '3.11' }} @@ -117,8 +117,6 @@ jobs: - browser: ${{ github.event.pull_request.draft && 'webkit' }} # There are many unexplained tests that fail on webkit w/ python 3.8, 3.9 # Given the more recent versions of python work, we will exclude this combination - - browser: "webkit" - python-version: "3.8" - browser: "webkit" python-version: "3.9" fail-fast: false @@ -157,7 +155,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.12", "3.11", "3.10", "3.9"] + python-version: ["3.13", "3.12", "3.11", "3.10", "3.9"] browser: ["chromium", "firefox", "webkit"] exclude: - python-version: ${{ github.event.pull_request.draft && '3.11' }} diff --git a/pyproject.toml b/pyproject.toml index c51a7d97f..0577e1ce6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] dependencies = [ "typing-extensions>=4.10.0", @@ -54,8 +55,8 @@ theme = ["libsass>=0.23.0", "brand_yml>=0.1.0"] test = [ "pytest>=6.2.4", "pytest-asyncio>=0.17.2", - "pytest-playwright>=0.3.0", - "playwright>=1.43.0", + "pytest-playwright>=0.5.2", + "playwright>=1.48.0", "pytest-xdist", "pytest-timeout", "pytest-rerunfailures", @@ -86,7 +87,10 @@ test = [ "faicons", "ridgeplot", "great_tables", - "modin[all]", + # modin depends on ray, which doesn't support Python 3.13 + "modin[all];python_version<'3.13'", + # ray doesn't currently support Python 3.13 + "ray;python_version<'3.13'", "polars", "dask[dataframe]", "pyarrow", diff --git a/shiny/_datastructures.py b/shiny/_datastructures.py index f2ac287ef..2a243d418 100644 --- a/shiny/_datastructures.py +++ b/shiny/_datastructures.py @@ -15,8 +15,6 @@ class PriorityQueueFIFO(Generic[T]): """ def __init__(self) -> None: - # Using Tuple instead of tuple because in Python 3.8 and earlier, tuple isn't - # generic self._pq: PriorityQueue[tuple[int, int, T]] = PriorityQueue() self._counter: int = 0 diff --git a/shiny/_utils.py b/shiny/_utils.py index fc0eaa21f..728fd94ec 100644 --- a/shiny/_utils.py +++ b/shiny/_utils.py @@ -72,7 +72,7 @@ def sort_keys_length(x: dict[str, T], descending: bool = False) -> dict[str, T]: def guess_mime_type( - url: "str | os.PathLike[str]", + url: str | os.PathLike[str], default: str = "application/octet-stream", strict: bool = True, ) -> str: @@ -80,8 +80,6 @@ def guess_mime_type( Guess the MIME type of a file. This is a wrapper for mimetypes.guess_type, but it only returns the type (and not encoding), and it allows a default value. """ - # Note that in the parameters above, "os.PathLike[str]" is in quotes to avoid - # "TypeError: 'ABCMeta' object is not subscriptable", in Python<=3.8. if url: # Work around issue #1601, some installations of Windows 10 return text/plain # as the mime type for .js files diff --git a/shiny/render/_render.py b/shiny/render/_render.py index 5cd608f6a..88c796bfc 100644 --- a/shiny/render/_render.py +++ b/shiny/render/_render.py @@ -4,9 +4,6 @@ import os import sys import typing - -# `typing.Dict` sed for python 3.8 compatibility -# Can use `dict` in python >= 3.9 from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union, cast from htmltools import Tag, TagAttrValue, TagChild diff --git a/shiny/render/renderer/_renderer.py b/shiny/render/renderer/_renderer.py index b79009c91..ce3cf3e26 100644 --- a/shiny/render/renderer/_renderer.py +++ b/shiny/render/renderer/_renderer.py @@ -336,9 +336,6 @@ def _auto_register(self) -> None: self._auto_registered = True -# Not inheriting from `WrapAsync[[], IT]` as python 3.8 needs typing extensions that -# doesn't support `[]` for a ParamSpec definition. :-( Would be minimal/clean if we -# could do `class AsyncValueFn(WrapAsync[[], IT]):` class AsyncValueFn(Generic[IT]): """ App-supplied output value function which returns type `IT`. diff --git a/tests/playwright/shiny/components/data_frame/data_type/app.py b/tests/playwright/shiny/components/data_frame/data_type/app.py index 50c76b952..e18ede0b0 100644 --- a/tests/playwright/shiny/components/data_frame/data_type/app.py +++ b/tests/playwright/shiny/components/data_frame/data_type/app.py @@ -1,6 +1,13 @@ from __future__ import annotations -import modin.pandas as mpd # pyright: ignore[reportMissingTypeStubs] +import sys + +# Remove this conditional once modin is supported on Python 3.13 +if sys.version_info < (3, 13): + import modin.pandas as mpd # pyright: ignore[reportMissingTypeStubs] +else: + raise RuntimeError("This test is not supported on Python 3.13") + import narwhals.stable.v1 as nw import palmerpenguins # pyright: ignore[reportMissingTypeStubs] import polars as pl diff --git a/tests/playwright/shiny/components/data_frame/data_type/test_df_data_type.py b/tests/playwright/shiny/components/data_frame/data_type/test_df_data_type.py index d3c24e130..ff131eac9 100644 --- a/tests/playwright/shiny/components/data_frame/data_type/test_df_data_type.py +++ b/tests/playwright/shiny/components/data_frame/data_type/test_df_data_type.py @@ -1,5 +1,7 @@ import re +import sys +import pytest from playwright.sync_api import Page from shiny.playwright import controller @@ -39,6 +41,10 @@ ] +@pytest.mark.skipif( + sys.version_info[:2] == (3, 13), + reason="Skipping on Python 3.13, since modin is not supported on 3.13", +) def test_data_frame_data_type( page: Page, local_app: ShinyAppProc, diff --git a/tests/playwright/shiny/components/table/app.py b/tests/playwright/shiny/components/table/app.py index 1a2a2a4e9..4b101bd4c 100644 --- a/tests/playwright/shiny/components/table/app.py +++ b/tests/playwright/shiny/components/table/app.py @@ -1,6 +1,13 @@ from __future__ import annotations -import modin.pandas as md # pyright: ignore[reportMissingTypeStubs] +import sys + +# Remove this conditional once modin is supported on Python 3.13 +if sys.version_info < (3, 13): + import modin.pandas as md # pyright: ignore[reportMissingTypeStubs] +else: + # This block executes for Python 3.13 and above + raise RuntimeError("This test is not supported on Python 3.13") import narwhals.stable.v1 as nw import palmerpenguins # pyright: ignore[reportMissingTypeStubs] diff --git a/tests/playwright/shiny/components/table/test_table.py b/tests/playwright/shiny/components/table/test_table.py index d04bcd39d..0f5f27f15 100644 --- a/tests/playwright/shiny/components/table/test_table.py +++ b/tests/playwright/shiny/components/table/test_table.py @@ -1,11 +1,17 @@ import re +import sys +import pytest from playwright.sync_api import Page from shiny.playwright import controller from shiny.run import ShinyAppProc +@pytest.mark.skipif( + sys.version_info >= (3, 13), + reason="Skipping on Python 3.13 and above, since modin is not supported on these versions", +) def test_table_data_support(page: Page, local_app: ShinyAppProc) -> None: page.goto(local_app.url)