Skip to content

Commit

Permalink
build: drop py38 (#263)
Browse files Browse the repository at this point in the history
* build: drop py38

* bump min typing ext

* ignore cleanup warning from pyside6

* change minreq

* bump min

* fix for pint again
  • Loading branch information
tlambert03 authored Dec 13, 2024
1 parent 2f3113f commit 8a40170
Show file tree
Hide file tree
Showing 22 changed files with 99 additions and 63 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test_and_deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ jobs:
test-qt-minreqs:
uses: pyapp-kit/workflows/.github/workflows/test-pyrepo.yml@v2
with:
python-version: "3.8"
python-version: "3.9"
qt: pyqt5
pip-post-installs: "qtpy==1.1.0 typing-extensions==3.7.4.3"
pip-post-installs: "qtpy==1.1.0 typing-extensions==4.5.0" # 4.5.0 is just for pint
pip-install-flags: -e
coverage-upload: artifact

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pytest

All widgets must be well-tested, and should work on:

- Python 3.8 and above
- Python 3.9 and above
- PyQt5 (5.11 and above) & PyQt6
- PySide2 (5.11 and above) & PySide6
- macOS, Windows, & Linux
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ that are not provided in the native QtWidgets module.
Components are tested on:

- macOS, Windows, & Linux
- Python 3.8 and above
- Python 3.9 and above
- PyQt5 (5.11 and above) & PyQt6
- PySide2 (5.11 and above) & PySide6

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ QtWidgets module.
Components are tested on:

- macOS, Windows, & Linux
- Python 3.8 and above
- Python 3.9 and above
- PyQt5 (5.11 and above) & PyQt6
- PySide2 (5.11 and above) & PySide6

Expand Down
10 changes: 5 additions & 5 deletions examples/throttler_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"""

from typing import Deque
from collections import deque

from qtpy.QtCore import QRect, QSize, Qt, QTimer, Signal
from qtpy.QtGui import QPainter, QPen
Expand Down Expand Up @@ -65,8 +65,8 @@ def __init__(self, parent=None):
self._scrollTimer.timeout.connect(self._scroll)
self._scrollTimer.start()

self._signalActivations: Deque[int] = Deque()
self._throttledSignalActivations: Deque[int] = Deque()
self._signalActivations: deque[int] = deque()
self._throttledSignalActivations: deque[int] = deque()

def sizeHint(self):
return QSize(400, 200)
Expand All @@ -84,7 +84,7 @@ def _scroll(self):

self.update()

def scrollAndCut(self, v: Deque[int], cutoff: int):
def scrollAndCut(self, v: deque[int], cutoff: int):
L = len(v)
for p in range(L):
v[p] += 1
Expand Down Expand Up @@ -121,7 +121,7 @@ def paintEvent(self, event):
p.drawLine(0, h2, w, h2)
p.restore()

def _drawSignals(self, p: QPainter, v: Deque[int], color, yStart, yEnd):
def _drawSignals(self, p: QPainter, v: deque[int], color, yStart, yEnd):
p.save()
pen = QPen()
pen.setWidthF(2.0)
Expand Down
51 changes: 37 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ build-backend = "hatchling.build"
name = "superqt"
description = "Missing widgets and components for PyQt/PySide"
readme = "README.md"
requires-python = ">=3.8"
requires-python = ">=3.9"
license = { text = "BSD 3-Clause License" }
authors = [{ email = "[email protected]", name = "Talley Lambert" }]
keywords = [
Expand All @@ -28,7 +28,6 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"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",
Expand All @@ -41,13 +40,21 @@ dynamic = ["version"]
dependencies = [
"pygments>=2.4.0",
"qtpy>=1.1.0",
"typing-extensions >=3.7.4.3,!=3.10.0.0",
"typing-extensions >=3.7.4.3,!=3.10.0.0", # however, pint requires >4.5.0
]

# extras
# https://peps.python.org/pep-0621/#dependencies-optional-dependencies
[project.optional-dependencies]
test = ["pint", "pytest", "pytest-cov", "pytest-qt", "numpy", "cmap", "pyconify"]
test = [
"pint",
"pytest",
"pytest-cov",
"pytest-qt",
"numpy",
"cmap",
"pyconify",
]
dev = [
"ipython",
"ruff",
Expand All @@ -58,7 +65,13 @@ dev = [
"rich",
"types-Pygments",
]
docs = ["mkdocs-macros-plugin", "mkdocs-material", "mkdocstrings[python]", "pint", "cmap"]
docs = [
"mkdocs-macros-plugin",
"mkdocs-material",
"mkdocstrings[python]",
"pint",
"cmap",
]
quantity = ["pint"]
cmap = ["cmap >=0.1.1"]
pyside2 = ["pyside2"]
Expand Down Expand Up @@ -100,21 +113,30 @@ python = ["3.11"]

[[tool.hatch.envs.test.matrix]]
qt = ["pyside2", "pyqt5", "pyqt5.12"]
python = ["3.8"]
python = ["3.9"]

[tool.hatch.envs.test.overrides]
matrix.qt.extra-dependencies = [
{value = "pyside2", if = ["pyside2"]},
{value = "pyside6", if = ["pyside6"]},
{value = "pyqt5", if = ["pyqt5"]},
{value = "pyqt6", if = ["pyqt6"]},
{value = "pyqt5==5.12", if = ["pyqt5.12"]},
{ value = "pyside2", if = [
"pyside2",
] },
{ value = "pyside6", if = [
"pyside6",
] },
{ value = "pyqt5", if = [
"pyqt5",
] },
{ value = "pyqt6", if = [
"pyqt6",
] },
{ value = "pyqt5==5.12", if = [
"pyqt5.12",
] },
]

# https://github.com/charliermarsh/ruff
[tool.ruff]
line-length = 88
target-version = "py38"
target-version = "py39"
src = ["src", "tests"]

# https://docs.astral.sh/ruff/rules
Expand All @@ -132,7 +154,7 @@ select = [
"B", # flake8-bugbear
"A001", # flake8-builtins
"RUF", # ruff-specific rules
"TCH", # flake8-type-checking
"TC", # flake8-type-checking
"TID", # flake8-tidy-imports
]
ignore = [
Expand All @@ -159,6 +181,7 @@ filterwarnings = [
"ignore:QPixmapCache.find:DeprecationWarning:",
"ignore:SelectableGroups dict interface:DeprecationWarning",
"ignore:The distutils package is deprecated:DeprecationWarning",
"ignore:.*Skipping callback call set_result",
]

# https://mypy.readthedocs.io/en/stable/config_file.html
Expand Down
4 changes: 3 additions & 1 deletion src/superqt/cmap/_catalog_combo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Container
from typing import TYPE_CHECKING

from cmap import Colormap
from qtpy.QtCore import Qt, Signal
Expand All @@ -11,6 +11,8 @@
from ._cmap_utils import try_cast_colormap

if TYPE_CHECKING:
from collections.abc import Container

from cmap._catalog import Category, Interpolation
from qtpy.QtGui import QKeyEvent

Expand Down
4 changes: 3 additions & 1 deletion src/superqt/cmap/_cmap_combo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any, Sequence
from typing import TYPE_CHECKING, Any

from cmap import Colormap
from qtpy.QtCore import Qt, Signal
Expand All @@ -23,6 +23,8 @@
from ._cmap_utils import try_cast_colormap

if TYPE_CHECKING:
from collections.abc import Sequence

from cmap._colormap import ColorStopsLike


Expand Down
5 changes: 4 additions & 1 deletion src/superqt/combobox/_color_combobox.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import warnings
from contextlib import suppress
from enum import IntEnum, auto
from typing import Any, Literal, Sequence, cast
from typing import TYPE_CHECKING, Any, Literal, cast

from qtpy.QtCore import QModelIndex, QPersistentModelIndex, QRect, QSize, Qt, Signal
from qtpy.QtGui import QColor, QPainter
Expand All @@ -19,6 +19,9 @@

from superqt.utils import signals_blocked

if TYPE_CHECKING:
from collections.abc import Sequence

_NAME_MAP = {QColor(x).name(): x for x in QColor.colorNames()}

COLOR_ROLE = Qt.ItemDataRole.BackgroundRole
Expand Down
4 changes: 2 additions & 2 deletions src/superqt/combobox/_enum_combobox.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from functools import reduce
from itertools import combinations
from operator import or_
from typing import Optional, Tuple, TypeVar
from typing import Optional, TypeVar

from qtpy.QtCore import Signal
from qtpy.QtWidgets import QComboBox
Expand Down Expand Up @@ -47,7 +47,7 @@ def _get_name(enum_value: Enum):
return name


def _get_name_with_value(enum_value: Enum) -> Tuple[str, Enum]:
def _get_name_with_value(enum_value: Enum) -> tuple[str, Enum]:
return _get_name(enum_value), enum_value


Expand Down
6 changes: 2 additions & 4 deletions src/superqt/elidable/_eliding.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import List

from qtpy.QtCore import Qt
from qtpy.QtGui import QFont, QFontMetrics, QTextLayout

Expand Down Expand Up @@ -36,7 +34,7 @@ def setEllipsesWidth(self, width: int) -> None:
self._ellipses_width = width

@staticmethod
def wrapText(text, width, font=None) -> List[str]:
def wrapText(text, width, font=None) -> list[str]:
"""Returns `text`, split as it would be wrapped for `width`, given `font`.
Static method.
Expand Down Expand Up @@ -74,5 +72,5 @@ def _elidedText(self) -> str:
# join them
return "".join(text[:nlines] + [last_line])

def _wrappedText(self) -> List[str]:
def _wrappedText(self) -> list[str]:
return _GenericEliding.wrapText(self._text, self.width(), self.font())
5 changes: 3 additions & 2 deletions src/superqt/fonticon/_iconfont.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Mapping, Type, Union
from collections.abc import Mapping
from typing import Union

FONTFILE_ATTR = "__font_file__"

Expand Down Expand Up @@ -69,7 +70,7 @@ class FA5S(IconFont):
__font_file__ = "..."


def namespace2font(namespace: Union[Mapping, Type], name: str) -> Type[IconFont]:
def namespace2font(namespace: Union[Mapping, type], name: str) -> type[IconFont]:
"""Convenience to convert a namespace (class, module, dict) into an IconFont."""
if isinstance(namespace, type):
if not isinstance(getattr(namespace, FONTFILE_ATTR), str):
Expand Down
14 changes: 7 additions & 7 deletions src/superqt/fonticon/_plugins.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import contextlib
from typing import ClassVar, Dict, List, Set, Tuple
from typing import ClassVar

from ._iconfont import IconFontMeta, namespace2font

Expand All @@ -11,9 +11,9 @@

class FontIconManager:
ENTRY_POINT: ClassVar[str] = "superqt.fonticon"
_PLUGINS: ClassVar[Dict[str, EntryPoint]] = {}
_LOADED: ClassVar[Dict[str, IconFontMeta]] = {}
_BLOCKED: ClassVar[Set[EntryPoint]] = set()
_PLUGINS: ClassVar[dict[str, EntryPoint]] = {}
_LOADED: ClassVar[dict[str, IconFontMeta]] = {}
_BLOCKED: ClassVar[set[EntryPoint]] = set()

def _discover_fonts(self) -> None:
self._PLUGINS.clear()
Expand Down Expand Up @@ -86,15 +86,15 @@ def dict(self) -> dict:
get_font_class = _manager._get_font_class


def discover() -> Tuple[str]:
def discover() -> tuple[str]:
_manager._discover_fonts()


def available() -> Tuple[str]:
def available() -> tuple[str]:
return tuple(_manager._PLUGINS)


def loaded(load_all=False) -> Dict[str, List[str]]:
def loaded(load_all=False) -> dict[str, list[str]]:
if load_all:
discover()
for x in available():
Expand Down
9 changes: 5 additions & 4 deletions src/superqt/fonticon/_qfont_icon.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import warnings
from collections import abc, defaultdict
from collections.abc import Sequence
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING, ClassVar, DefaultDict, Sequence, Tuple, Union, cast
from typing import TYPE_CHECKING, ClassVar, Union, cast

from qtpy import QT_VERSION
from qtpy.QtCore import QObject, QPoint, QRect, QSize, Qt
Expand Down Expand Up @@ -47,8 +48,8 @@ def __repr__(self) -> str:
int,
str,
Qt.GlobalColor,
Tuple[int, int, int, int],
Tuple[int, int, int],
tuple[int, int, int, int],
tuple[int, int, int],
None,
]

Expand Down Expand Up @@ -159,7 +160,7 @@ class _QFontIconEngine(QIconEngine):
def __init__(self, options: _IconOptions):
super().__init__()
self._opts: defaultdict[QIcon.State, dict[QIcon.Mode, _IconOptions | None]] = (
DefaultDict(dict)
defaultdict(dict)
)
self._opts[QIcon.State.Off][QIcon.Mode.Normal] = options
self.update_hash()
Expand Down
3 changes: 2 additions & 1 deletion src/superqt/selection/_searchable_tree_widget.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from typing import Any, Iterable, Mapping
from collections.abc import Iterable, Mapping
from typing import Any

from qtpy.QtCore import QRegularExpression
from qtpy.QtWidgets import QLineEdit, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget
Expand Down
Loading

0 comments on commit 8a40170

Please sign in to comment.