1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
From: Roland Mas <roland.mas@entierement.net>
Date: Fri, 2 Jan 2026 14:13:13 +0100
Subject: Python 3.14 compatibility
Partial backport of upstream's pull request at
https://github.com/pyapp-kit/magicgui/pull/721
---
.github/workflows/deploy_docs.yml | 1 +
.github/workflows/test_and_deploy.yml | 10 +++++-----
pyproject.toml | 7 +++++--
src/magicgui/signature.py | 17 +++++++++++------
tests/conftest.py | 12 ++++++++++++
5 files changed, 34 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml
index f8f3ad2..7767233 100644
--- a/.github/workflows/deploy_docs.yml
+++ b/.github/workflows/deploy_docs.yml
@@ -17,6 +17,7 @@ jobs:
fetch-depth: 0
- uses: astral-sh/setup-uv@v6
with:
+ python-version: "3.13"
enable-cache: true
- name: Deploy docs to GitHub Pages
diff --git a/.github/workflows/test_and_deploy.yml b/.github/workflows/test_and_deploy.yml
index d20e606..bf007d2 100644
--- a/.github/workflows/test_and_deploy.yml
+++ b/.github/workflows/test_and_deploy.yml
@@ -23,7 +23,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- python-version: ["3.10", "3.11"]
+ python-version: ["3.10", "3.13"]
os: [ubuntu-latest, macos-latest, windows-latest]
add-group: [pyqt6, pyside6]
include:
@@ -37,11 +37,11 @@ jobs:
- python-version: "3.9"
os: ubuntu-latest
add-group: pyside2
- - python-version: "3.11"
+ - python-version: "3.12"
os: windows-latest
add-group: pyqt5
- python-version: "3.10"
- os: ubuntu-latest
+ os: windows-latest
add-group: pyside2
- python-version: "3.12"
os: ubuntu-latest
@@ -49,10 +49,10 @@ jobs:
- python-version: "3.12"
os: ubuntu-latest
add-group: pyside6
- - python-version: "3.13"
+ - python-version: "3.14"
os: ubuntu-latest
add-group: pyside6
- - python-version: "3.13"
+ - python-version: "3.14"
os: windows-latest
add-group: pyqt6
steps:
diff --git a/pyproject.toml b/pyproject.toml
index bfb954c..ad3b82e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,6 +28,7 @@ classifiers = [
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
+ "Programming Language :: Python :: 3.14",
"Topic :: Desktop Environment",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",
@@ -65,6 +66,7 @@ third-party-support = [
"attrs>=25.3.0",
"ipykernel>=6.29.5",
"matplotlib>=3.9.4",
+ "numpy>=2.1.0; python_version >= '3.13'",
"numpy>=1.26.4",
"pandas>=2.2.3; python_version >= '3.11'",
"pandas>=2.1",
@@ -81,7 +83,7 @@ test = [
test-qt = [{ include-group = "test" }, "pytest-qt >=4.3.0"]
pyqt5 = ["magicgui[pyqt5]", { include-group = "test-qt" }]
pyqt6 = ["magicgui[pyqt6]", { include-group = "test-qt" }]
-pyside2 = ["magicgui[pyside2]", { include-group = "test-qt" }]
+pyside2 = ["magicgui[pyside2]", { include-group = "test-qt" }, "numpy<2; python_version < '3.13'"]
pyside6 = ["magicgui[pyside6]", { include-group = "test-qt" }]
dev = [
{ include-group = "test" },
@@ -131,7 +133,7 @@ line-length = 88
target-version = "py39"
src = ["src", "tests"]
fix = true
-# unsafe-fixes = true
+unsafe-fixes = true
[tool.ruff.lint]
pydocstyle = { convention = "numpy" }
@@ -179,6 +181,7 @@ filterwarnings = [
"ignore:Jupyter is migrating:DeprecationWarning",
"ignore:The `ipykernel.comm.Comm` class has been deprecated",
"ignore:.*read_binary is deprecated:",
+ "ignore::DeprecationWarning:matplotlib",
]
# https://mypy.readthedocs.io/en/stable/config_file.html
diff --git a/src/magicgui/signature.py b/src/magicgui/signature.py
index d67ed6a..3a84cb8 100644
--- a/src/magicgui/signature.py
+++ b/src/magicgui/signature.py
@@ -182,14 +182,19 @@ class MagicParameter(inspect.Parameter):
rep = rep.replace(": NoneType = ", "=")
return rep
- def __str__(self) -> str:
- """Return string representation of the Parameter in a signature."""
+ def _format(self, *, quote_annotation_strings: bool = True) -> str:
+ """Return formatted string for use in Signature.format() (Python 3.14+)."""
hint, _ = get_args(self.annotation)
- return str(
- inspect.Parameter(
- self.name, self.kind, default=self.default, annotation=hint
- )
+ param = inspect.Parameter(
+ self.name, self.kind, default=self.default, annotation=hint
)
+ if hasattr(param, "_format"): # python 3.14+
+ return param._format(quote_annotation_strings=quote_annotation_strings) # type: ignore[no-any-return]
+ return str(param)
+
+ def __str__(self) -> str:
+ """Return string representation of the Parameter in a signature."""
+ return self._format()
def to_widget(
self,
diff --git a/tests/conftest.py b/tests/conftest.py
index b2ed66d..23c6a48 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,7 +1,19 @@
+import os
+
import pytest
from magicgui.application import use_app
+# Disable tqdm's TMonitor thread to prevent race conditions with Qt threading
+# that can cause intermittent segfaults on CI (especially with PySide6 on Linux).
+# See: https://github.com/tqdm/tqdm/issues/469
+try:
+ from tqdm import tqdm as _tqdm_std
+
+ _tqdm_std.monitor_interval = 0
+except ImportError:
+ pass
+
@pytest.fixture(scope="session")
def qapp():
|