From 97539cc3bf65ba4ed0fdd58df9d5f91fac15c168 Mon Sep 17 00:00:00 2001 From: PD Hall <20580126+pdhall99@users.noreply.github.com> Date: Wed, 21 Oct 2026 12:20:13 +0100 Subject: [PATCH] Make Python 3.11 the minimum supported version --- .github/workflows/ci.yml | 4 +- .pre-commit-config.yaml | 15 ++- README.md | 30 +++--- docs/CHANGELOG.md | 4 + docs/CONTRIBUTING.md | 4 +- pyproject.toml | 209 +++++++++++++++++++++------------------ src/spanmark/_session.py | 3 +- 7 files changed, 147 insertions(+), 122 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0329ec4..0cbdfa3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ permissions: env: RUNNER: &runner "ubuntu-24.04" JOB_TIMEOUT: &job_timeout 30 - TOOL_PYTHON_VERSION: "3.10" + TOOL_PYTHON_VERSION: "3.11" HATCH_VERSION: "1.18.1" UV_VERSION: "0.13.4" DISTRIBUTION_NAME: "spanmark" @@ -52,6 +52,8 @@ jobs: run: uv tool install "hatch==$HATCH_VERSION" - name: Run pre-commit + env: + GH_TOKEN: ${{ github.token }} run: hatch run pre-commit:ci discover-tests: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 53d720c..80a0d4d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,5 @@ default_language_version: - python: python3.10 + python: python3.11 repos: - repo: https://github.com/pre-commit/pre-commit-hooks @@ -21,16 +21,21 @@ repos: - id: trailing-whitespace args: [--markdown-linebreak-ext=md] + - repo: https://github.com/tox-dev/pyproject-fmt + rev: v2.30.3 + hooks: + - id: pyproject-fmt + - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.16.6 # keep consistent with hatch config + rev: v0.17.1 # keep consistent with hatch config hooks: # Run the linter - id: ruff-check - types_or: [python, pyi, jupyter] + types_or: [python, pyi, jupyter, markdown] args: [--fix, --config=pyproject.toml] # Run the formatter - id: ruff-format - types_or: [python, pyi, jupyter] + types_or: [python, pyi, jupyter, markdown] args: [--config=pyproject.toml] - repo: https://github.com/rhysd/actionlint @@ -39,7 +44,7 @@ repos: - id: actionlint - repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: v1.29.0 + rev: v1.31.1 hooks: - id: zizmor diff --git a/README.md b/README.md index d6e59c2..37c309d 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Such datasets are needed for the training and evaluation of **span recognition** ## Installation -`spanmark` requires Python 3.10 or later (see [compatibility and versioning](#compatibility-and-versioning)). +`spanmark` requires Python 3.11 or later (see [compatibility and versioning](#compatibility-and-versioning)). Install the latest release from [PyPI](https://pypi.org/project/spanmark/): @@ -159,19 +159,19 @@ Prepare a sequence of documents: ```python { - "id": "doc-1", - "text": "Alice joined Acme.", - "meta": { - "source": "demo" - }, - "suggestions": [ - { - "start": 0, - "end": 5, - "label": "PERSON", - "score": 0.97 - } - ] + "id": "doc-1", + "text": "Alice joined Acme.", + "meta": { + "source": "demo", + }, + "suggestions": [ + { + "start": 0, + "end": 5, + "label": "PERSON", + "score": 0.97, + } + ], } ``` @@ -273,7 +273,7 @@ The output JSONL contains one document record per line, for example: {"start": 13, "end": 17, "label": "ORG", "source": "user"} ], "answer": "accept", - "flagged": false + "flagged": false, } } ``` diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 74b8814..1ecdf00 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Removed + +- Support for Python 3.10, making Python 3.11 the minimum supported version + ## [0.1.1] - 2026-09-10 ### Fixed diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 7ab4342..bc633be 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -56,7 +56,7 @@ For code contributions you will need: - A GitHub account - A development environment with: - - Python 3.10 (the minimum version of Python supported) + - Python 3.11 (the minimum version of Python supported) - `hatch>=1.17` - Access to the internet for GitHub and installation of packages from PyPI @@ -99,7 +99,7 @@ Only the checks and definition-of-done items relevant to the change need to appl hatch test tests/test_foo.py # One file hatch test tests/test_foo.py::test_bar # One test hatch test -k roundtrip # Tests matching an expression -hatch test --python 3.10 tests/test_foo.py # One file, one Python version +hatch test --python 3.11 tests/test_foo.py # One file, one Python version ``` Use these commands for a fast iterative development loop. diff --git a/pyproject.toml b/pyproject.toml index 17285de..f745cf0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,18 +1,14 @@ # [build-system] [build-system] -requires = ["hatchling", "hatch-vcs"] build-backend = "hatchling.build" +requires = [ "hatch-vcs", "hatchling" ] # -------------------------------------------------------------------------------------- # [project] [project] name = "spanmark" -dynamic = ["version"] description = "A lightweight span-annotation widget for interactive Python environments" readme = { file = "README.md", content-type = "text/markdown" } -requires-python = ">=3.10" -license = "MIT" -license-files = ["LICENSE"] keywords = [ "annotation", "anywidget", @@ -33,9 +29,9 @@ keywords = [ "text labelling", "widget", ] -authors = [ - { name = "PD Hall", email = "20580126+pdhall99@users.noreply.github.com" }, -] +license = "MIT" +license-files = [ "LICENSE" ] +requires-python = ">=3.11" classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", @@ -43,21 +39,25 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "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", + "Programming Language :: Python :: 3.15", "Typing :: Typed", ] +dynamic = [ "version" ] dependencies = [ "anywidget", "filelock>=3.16", "ipython", "traitlets", - "typing-extensions", ] +[[project.authors]] +name = "PD Hall" +email = "20580126+pdhall99@users.noreply.github.com" + [project.urls] Homepage = "https://github.com/pdhall99/spanmark" Documentation = "https://github.com/pdhall99/spanmark/blob/main/README.md" @@ -68,18 +68,15 @@ Changelog = "https://github.com/pdhall99/spanmark/blob/main/docs/CHANGELOG.md" # -------------------------------------------------------------------------------------- # [dependency-groups] [dependency-groups] -check-code = ["ruff==0.16.6"] # keep consistent with pre-commit-config.yaml -check-fmt = [{ "include-group" = "check-code" }] -check-types = ["pyrefly==1.2.0", { "include-group" = "test" }] dev = [ - { "include-group" = "check-code" }, - { "include-group" = "check-fmt" }, - { "include-group" = "check-types" }, - { "include-group" = "test" }, + { include-group = "check-code" }, + { include-group = "check-fmt" }, + { include-group = "check-types" }, + { include-group = "test" }, ] test = [ - "coverage-enable-subprocess==1.0", "coverage[toml]~=7.11", + "coverage-enable-subprocess==1", "pytest~=9.0", "pytest-mock~=3.12", "pytest-randomly~=4.1", @@ -87,29 +84,19 @@ test = [ "pytest-sugar", "pytest-xdist[psutil]~=3.5", ] +check-code = [ "ruff==0.17.1" ] # keep consistent with pre-commit-config.yaml +check-fmt = [ { include-group = "check-code" } ] +check-types = [ "pyrefly==1.4", { include-group = "test" } ] -# -------------------------------------------------------------------------------------- -# [tool.coverage] -[tool.coverage.run] -source_pkgs = ["spanmark"] -omit = ["*/_version.py"] -branch = true -parallel = true +[tool.hatch.version.raw-options] +version_scheme = "no-guess-dev" +local_scheme = "no-local-version" -[tool.coverage.paths] -spanmark = ["src/spanmark", "*/site-packages/spanmark"] +[tool.hatch.version] +source = "vcs" -[tool.coverage.report] -exclude_lines = [ - "no cov", - "if __name__ == .__main__.:", - "if TYPE_CHECKING:", - "if 0:", - "raise NotImplementedError", - "raise AssertionError", - "if self\\.debug", - ".*\\.\\.\\.$", -] +[tool.hatch.metadata] +allow-direct-references = true # -------------------------------------------------------------------------------------- # [tool.hatch] @@ -117,53 +104,53 @@ exclude_lines = [ version-file = "src/spanmark/_version.py" [tool.hatch.build.targets.sdist] -exclude = [".github"] +exclude = [ ".github" ] [tool.hatch.build.targets.wheel] -packages = ["src/spanmark"] +packages = [ "src/spanmark" ] [tool.hatch.envs.default] -python = "3.10" +python = "3.11" installer = "uv" dependencies = [] [tool.hatch.envs.dev] -dependency-groups = ["dev"] -post-install-commands = ["hatch run pre-commit:install"] dependencies = [] +post-install-commands = [ "hatch run pre-commit:install" ] +dependency-groups = [ "dev" ] [tool.hatch.envs.hatch-check-code] -config-path = "pyproject.toml" -dependency-groups = ["check-code"] dependencies = [] +config-path = "pyproject.toml" +dependency-groups = [ "check-code" ] [tool.hatch.envs.hatch-check-fmt] -config-path = "pyproject.toml" -dependency-groups = ["check-fmt"] dependencies = [] +config-path = "pyproject.toml" +dependency-groups = [ "check-fmt" ] [tool.hatch.envs.hatch-check-types] -python = "3.10" -config-path = "pyproject.toml" -dependency-groups = ["check-types"] +python = "3.11" dependencies = [] +config-path = "pyproject.toml" +dependency-groups = [ "check-types" ] [tool.hatch.envs.hatch-test] -dependency-groups = ["test"] dependencies = [] +dependency-groups = [ "test" ] [[tool.hatch.envs.hatch-test.matrix]] -python = ["3.10", "3.11", "3.12", "3.13", "3.14"] +python = [ "3.11", "3.12", "3.13", "3.14", "3.15" ] [tool.hatch.envs.hatch-test.scripts] -run = "pytest{env:HATCH_TEST_ARGS:} {args}" -run-cov = "coverage run -m pytest{env:HATCH_TEST_ARGS:} {args}" cov-combine = "coverage combine" -cov-report = ["coverage report {args}", "coverage html"] +cov-report = [ "coverage report {args}", "coverage html" ] cov-report-markdown = "coverage report --format=markdown" +run = "pytest{env:HATCH_TEST_ARGS:} {args}" +run-cov = "coverage run -m pytest{env:HATCH_TEST_ARGS:} {args}" [tool.hatch.envs.notebook] -dependencies = ["anywidget", "ipywidgets", "jupyterlab", "pip"] +dependencies = [ "anywidget", "ipywidgets", "jupyterlab", "pip" ] [tool.hatch.envs.notebook.scripts] lab = "jupyter lab" @@ -171,74 +158,102 @@ lab = "jupyter lab" [tool.hatch.envs.pre-commit] detached = true skip-install = true -dependencies = ["pre-commit"] +dependencies = [ "pre-commit" ] [tool.hatch.envs.pre-commit.scripts] +ci = "pre-commit run --all-files" install = "pre-commit install" run = "pre-commit run --all {args}" -ci = "pre-commit run --all-files" - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.hatch.version] -source = "vcs" - -[tool.hatch.version.raw-options] -version_scheme = "no-guess-dev" -local_scheme = "no-local-version" - -# -------------------------------------------------------------------------------------- -# [tool.pyrefly] -[tool.pyrefly] -python-version = "3.10" -preset = "strict" -project-includes = ["src/spanmark", "tests"] -search-path = ["src"] -disable-search-path-heuristics = true -errors = { implicit-any-lambda = "ignore" } - -# -------------------------------------------------------------------------------------- -# [tool.pytest] -[tool.pytest.ini_options] -addopts = "-ra -q --doctest-glob='*.md'" -testpaths = ["README.md", "tests"] # -------------------------------------------------------------------------------------- # [tool.ruff] [tool.ruff] -target-version = "py310" +target-version = "py311" line-length = 88 indent-width = 4 -src = ["src"] -include = ["scripts/**/*.py", "src/**/*.py", "src/**/*.pyi", "tests/**/*.py"] -exclude = ["**/_version.py"] +src = [ "src" ] +include = [ "scripts/**/*.py", "src/**/*.py", "src/**/*.pyi", "tests/**/*.py" ] +exclude = [ "**/_version.py" ] [tool.ruff.format] quote-style = "double" +[tool.ruff.lint.per-file-ignores] +"__init__.py" = [ "F401" ] + +[tool.ruff.lint.flake8-quotes] +inline-quotes = "double" + +[tool.ruff.lint.pydocstyle] +convention = "google" + [tool.ruff.lint] -select = ["D", "E", "F", "I", "UP", "W"] +select = [ "D", "E", "F", "I", "UP", "W" ] ignore = [ "D1", - "D205", - "E203", # Below as recommended at https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules "D203", + "D205", "D206", "D300", "E111", "E114", "E117", + "E203", "E501", "W191", ] -[tool.ruff.lint.flake8-quotes] -inline-quotes = "double" +# -------------------------------------------------------------------------------------- +# [tool.pyproject-fmt] +[tool.pyproject-fmt] +column_width = 88 +indent = 4 +keep_full_version = false +generate_python_version_classifiers = false +max_supported_python = "3.14" +table_format = "long" +sub_table_spacing = "\n" +separate_root_table = "\n" +expand_tables = [] +collapse_tables = [] +skip_wrap_for_keys = [] -[tool.ruff.lint.per-file-ignores] -"__init__.py" = ["F401"] +# -------------------------------------------------------------------------------------- +# [tool.pyrefly] +[tool.pyrefly] +python-version = "3.11" +project-includes = [ "src/spanmark", "tests" ] +search-path = [ "src" ] +errors = { implicit-any-lambda = "ignore" } +disable-search-path-heuristics = true +preset = "strict" -[tool.ruff.lint.pydocstyle] -convention = "google" +# -------------------------------------------------------------------------------------- +# [tool.pytest] +[tool.pytest.ini_options] +testpaths = [ "README.md", "tests" ] +addopts = "-ra -q --doctest-glob='*.md'" + +# -------------------------------------------------------------------------------------- +# [tool.coverage] +[tool.coverage.run] +source_pkgs = [ "spanmark" ] +omit = [ "*/_version.py" ] +branch = true +parallel = true + +[tool.coverage.paths] +spanmark = [ "src/spanmark", "*/site-packages/spanmark" ] + +[tool.coverage.report] +exclude_lines = [ + ".*\\.\\.\\.$", + "if __name__ == .__main__.:", + "if 0:", + "if self\\.debug", + "if TYPE_CHECKING:", + "no cov", + "raise AssertionError", + "raise NotImplementedError", +] diff --git a/src/spanmark/_session.py b/src/spanmark/_session.py index 46bb8a1..1b08295 100644 --- a/src/spanmark/_session.py +++ b/src/spanmark/_session.py @@ -8,11 +8,10 @@ from dataclasses import replace from pathlib import Path from types import TracebackType -from typing import Any, TypeAlias, cast +from typing import Any, Self, TypeAlias, cast from filelock import FileLock, Timeout from IPython.display import display -from typing_extensions import Self from spanmark._autosave import AUTOSAVE_CHECKPOINT_BYTES, AutosaveOverlay from spanmark._model import (