What changed, and why it matters
This commit simply removes support for Python 3.9 from the project. It updates configuration files to require Python 3.10 or newer, removes a Python 3.9 Docker test image, and cleans up dependency lock files that were only needed for Python 3.9. There is no code change that fixes or introduces a security vulnerability.
No security action required. Users still on Python 3.9 will need to upgrade to Python 3.10+ to install future releases, but this is a documented compatibility change, not a security patch.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff is a maintenance-only change: .github/workflows/device-test.yml drops ‘3.9’ from the test matrix; .python-version moves to 3.10.20; ci/py39.Dockerfile is deleted; pyproject.toml and setup.py change python_requires from ‘>=3.9,<3.13’ to ‘>=3.10,<3.13’; poetry.lock is regenerated with Python 3.9-only packages (importlib-metadata, zipp) removed and PySide2/shiboken2/tomli markers narrowed from ‘<3.11’ to ‘==3.10’; test/setup_environment.sh only updates a comment. No application source code is modified.
Changed components
CI/test configurationPackaging metadata (pyproject.toml, setup.py, poetry.lock)Python version support matrixInspect captured patch +10 / −74
diff --git a/.github/workflows/device-test.yml b/.github/workflows/device-test.yml
index 5232314..5ec9ede 100644
--- a/.github/workflows/device-test.yml
+++ b/.github/workflows/device-test.yml
@@ -18,7 +18,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- python-version: ['3.9', '3.10', '3.11', '3.12']
+ python-version: ['3.10', '3.11', '3.12']
device:
- ${{ inputs.device }}
test:
diff --git a/.python-version b/.python-version
index bd28b9c..44677e5 100644
--- a/.python-version
+++ b/.python-version
@@ -1 +1 @@
-3.9
+3.10.20
diff --git a/ci/py39.Dockerfile b/ci/py39.Dockerfile
deleted file mode 100644
index 9c6f5ee..0000000
--- a/ci/py39.Dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-# Cache break (modify this line to break cirrus' dockerfile build cache) 1
-
-FROM python:3.9
-
-ENV DEBIAN_FRONTEND=noninteractive
-RUN apt-get update
-RUN apt-get install -y \
- cython3 \
- git \
- libpcsclite-dev \
- libsdl2-dev \
- libsdl2-image-dev \
- libslirp-dev \
- libudev-dev \
- libusb-1.0-0-dev \
- qemu-user-static \
- swig
-
-RUN pip install poetry flake8
-
-ENV LC_ALL=C.UTF-8
-ENV LANG=C.UTF-8
-ENV LANGUAGE=C.UTF-8
diff --git a/poetry.lock b/poetry.lock
index d0f4916..b26f93c 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -507,27 +507,6 @@ files = [
{file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
]
-[[package]]
-name = "importlib-metadata"
-version = "7.0.1"
-description = "Read metadata from Python packages"
-optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
-markers = "python_version == \"3.9\""
-files = [
- {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"},
- {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"},
-]
-
-[package.dependencies]
-zipp = ">=0.5"
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
-perf = ["ipython"]
-testing = ["flufl.flake8", "importlib-resources (>=1.3) ; python_version < \"3.9\"", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\"", "pytest-perf (>=0.9.2)", "pytest-ruff"]
-
[[package]]
name = "jinja2"
version = "3.1.3"
@@ -882,7 +861,6 @@ files = [
[package.dependencies]
altgraph = "*"
-importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""}
packaging = ">=22.0"
pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""}
@@ -907,7 +885,6 @@ files = [
]
[package.dependencies]
-importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
packaging = ">=22.0"
setuptools = ">=42.0.0"
@@ -933,7 +910,7 @@ description = "Python bindings for the Qt cross-platform application and UI fram
optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.11"
groups = ["main"]
-markers = "python_version < \"3.11\" and extra == \"qt\""
+markers = "python_version == \"3.10\" and extra == \"qt\""
files = [
{file = "PySide2-5.15.2.1-5.15.2-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:b5e1d92f26b0bbaefff67727ccbb2e1b577f2c0164b349b3d6e80febb4c5bde2"},
{file = "PySide2-5.15.2.1-5.15.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:235240b6ec8206d9fdf0232472c6ef3241783d480425e5b54796f06e39ed23da"},
@@ -1017,7 +994,7 @@ description = "Python / C++ bindings helper module"
optional = true
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <3.11"
groups = ["main"]
-markers = "python_version < \"3.11\" and extra == \"qt\""
+markers = "python_version == \"3.10\" and extra == \"qt\""
files = [
{file = "shiboken2-5.15.2.1-5.15.2-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:f890f5611ab8f48b88cfecb716da2ac55aef99e2923198cefcf781842888ea65"},
{file = "shiboken2-5.15.2.1-5.15.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:87079c07587859a525b9800d60b1be971338ce9b371d6ead81f15ee5a46d448b"},
@@ -1069,7 +1046,6 @@ babel = ">=2.9"
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
docutils = ">=0.18.1,<0.21"
imagesize = ">=1.3"
-importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""}
Jinja2 = ">=3.0"
packaging = ">=21.0"
Pygments = ">=2.13"
@@ -1252,7 +1228,7 @@ description = "A lil' TOML parser"
optional = false
python-versions = ">=3.7"
groups = ["dev"]
-markers = "python_version < \"3.11\""
+markers = "python_version == \"3.10\""
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
@@ -1288,27 +1264,10 @@ h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
-[[package]]
-name = "zipp"
-version = "3.17.0"
-description = "Backport of pathlib-compatible object wrapper for zip files"
-optional = false
-python-versions = ">=3.8"
-groups = ["dev"]
-markers = "python_version == \"3.9\""
-files = [
- {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"},
- {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"},
-]
-
-[package.extras]
-docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"]
-testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7) ; platform_python_implementation != \"PyPy\"", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1) ; platform_python_implementation != \"PyPy\"", "pytest-ruff"]
-
[extras]
qt = ["pyside2"]
[metadata]
lock-version = "2.1"
-python-versions = "^3.9,<3.13"
-content-hash = "f1695383c9bf2a946924a19c7aaeda082e6160a43932173e989129ad6794be95"
+python-versions = "^3.10,<3.13"
+content-hash = "32c83e332e591f7a95b48ef02297798399287c93bc25be7730a25f84d20b4f2b"
diff --git a/pyproject.toml b/pyproject.toml
index eaf34ca..618a14b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -16,7 +16,7 @@ packages = [
]
[tool.poetry.dependencies]
-python = "^3.9,<3.13"
+python = "^3.10,<3.13"
hidapi = ">=0.14.0"
ecdsa = "~0"
pyaes = "^1.6"
diff --git a/setup.py b/setup.py
index 79c1cd5..8ea9d70 100644
--- a/setup.py
+++ b/setup.py
@@ -60,7 +60,7 @@ setup_kwargs = {
'install_requires': install_requires,
'extras_require': extras_require,
'entry_points': entry_points,
- 'python_requires': '>=3.9,<3.13',
+ 'python_requires': '>=3.10,<3.13',
}
diff --git a/test/setup_environment.sh b/test/setup_environment.sh
index 36788bf..069b238 100755
--- a/test/setup_environment.sh
+++ b/test/setup_environment.sh
@@ -69,7 +69,7 @@ TREZOR_VERSION="core/v2.9.6"
BITBOX01_VERSION="v7.1.0"
BITBOX02_VERSION="firmware/v9.24.0"
KEEPKEY_VERSION="v7.10.0"
-SPECULOS_VERSION="v0.25.10" # Last version supporting Python 3.9 (v0.25.11+ requires >=3.10)
+SPECULOS_VERSION="v0.25.10" # v0.25.11+ requires Python >=3.10
JADE_VERSION="1.0.36"
# Keep COLDCARD_VERSION in sync with .github/actions/install-sim/action.yml
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.