style: use ruff format instead of black, update pre-commit, restrict pyside6 tests (#235)

* style: use ruff format

* fix import

* disallow pyside 6.6.2

* pin in tests too

* pyside6.4 on windows

* fix greedy imports

* double quote

* run sliders last

* try 6.6.1 again
This commit is contained in:
Talley Lambert
2024-03-06 15:42:51 -05:00
committed by GitHub
parent 56f65ff123
commit 16f9ef9d3d
30 changed files with 90 additions and 111 deletions

View File

@@ -38,18 +38,19 @@ jobs:
backend: pyside2
include:
# https://bugreports.qt.io/browse/PYSIDE-2627
- python-version: "3.10"
platform: macos-latest
backend: pyside6
backend: "'pyside6!=6.6.2'"
- python-version: "3.11"
platform: macos-latest
backend: pyside6
backend: "'pyside6!=6.6.2'"
- python-version: "3.10"
platform: windows-latest
backend: pyside6
backend: "'pyside6!=6.6.2'"
- python-version: "3.11"
platform: windows-latest
backend: pyside6
backend: "'pyside6!=6.6.2'"
- python-version: "3.12"
platform: macos-latest

View File

@@ -4,26 +4,15 @@ ci:
autoupdate_commit_msg: "ci: [pre-commit.ci] autoupdate"
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-docstring-first
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/psf/black
rev: 23.12.1
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.9
rev: v0.3.0
hooks:
- id: ruff
args: ["--fix"]
args: [--fix, --unsafe-fixes]
- id: ruff-format
- repo: https://github.com/abravalheri/validate-pyproject
rev: v0.15
rev: v0.16
hooks:
- id: validate-pyproject

View File

@@ -37,7 +37,7 @@ def define_env(env: "MacrosPlugin"):
)
src = src.replace("app.exec_()", "")
exec(src) # noqa: S102
exec(src)
_grab(dest, width)
return (
f"![{page.title}](../{dest.parent.name}/{dest.name})"

View File

@@ -1,4 +1,5 @@
"""Example for QCollapsible."""
from qtpy.QtWidgets import QApplication, QLabel, QPushButton
from superqt import QCollapsible

View File

@@ -49,7 +49,6 @@ dependencies = [
[project.optional-dependencies]
test = ["pint", "pytest", "pytest-cov", "pytest-qt", "numpy", "cmap", "pyconify"]
dev = [
"black",
"ipython",
"ruff",
"mypy",
@@ -66,7 +65,8 @@ pyside2 = ["pyside2"]
# see issues surrounding usage of Generics in pyside6.5.x
# https://github.com/pyapp-kit/superqt/pull/177
# https://github.com/pyapp-kit/superqt/pull/164
pyside6 = ["pyside6 !=6.5.0,!=6.5.1"]
# https://bugreports.qt.io/browse/PYSIDE-2627
pyside6 = ["pyside6 !=6.5.0,!=6.5.1,!=6.6.2"]
pyqt5 = ["pyqt5"]
pyqt6 = ["pyqt6"]
font-fa5 = ["fonticon-fontawesome5"]
@@ -111,49 +111,44 @@ matrix.qt.extra-dependencies = [
{value = "pyqt5==5.12", if = ["pyqt5.12"]},
]
# https://pycqa.github.io/isort/docs/configuration/options.html
[tool.isort]
profile = "black"
src_paths = ["src/superqt", "tests"]
# https://github.com/charliermarsh/ruff
[tool.ruff]
line-length = 88
target-version = "py38"
src = ["src", "tests"]
# https://docs.astral.sh/ruff/rules
[tool.ruff.lint]
pydocstyle = { convention = "numpy" }
select = [
"E", # style errors
"W", # style warnings
"F", # flakes
"W", # flakes
"D", # pydocstyle
"D417", # Missing argument descriptions in Docstrings
"I", # isort
"UP", # pyupgrade
"S", # bandit
"C4", # flake8-comprehensions
"B", # flake8-bugbear
"A001", # flake8-builtins
"RUF", # ruff-specific rules
"TID", # tidy imports
"TCH", # flake8-type-checking
"TID", # flake8-tidy-imports
]
ignore = [
"D100", # Missing docstring in public module
"D101", # Missing docstring in public class
"D104", # Missing docstring in public package
"D107", # Missing docstring in __init__
"D203", # 1 blank line required before class docstring
"D212", # Multi-line docstring summary should start at the first line
"D213", # Multi-line docstring summary should start at the second line
"D401", # First line should be in imperative mood
"D413", # Missing blank line after last section
"D416", # Section name should end with a colon
"D401", # First line should be in imperative mood (remove to opt in)
]
[tool.ruff.per-file-ignores]
[tool.ruff.lint.per-file-ignores]
"tests/*.py" = ["D", "S101"]
"examples/demo_widget.py" = ["E501"]
"examples/*.py" = ["B", "D"]
# https://docs.astral.sh/ruff/formatter/
[tool.ruff.format]
docstring-code-format = true
# https://docs.pytest.org/en/6.2.x/customize.html
[tool.pytest.ini_options]
minversion = "6.0"
@@ -189,6 +184,7 @@ allow_redefinition = true
source = ["superqt"]
[tool.coverage.report]
show_missing = true
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:",

View File

@@ -1,4 +1,5 @@
"""superqt is a collection of Qt components for python."""
from importlib.metadata import PackageNotFoundError, version
from typing import TYPE_CHECKING, Any
@@ -50,8 +51,8 @@ __all__ = [
]
if TYPE_CHECKING:
from .combobox import QColormapComboBox
from .spinbox._quantity import QQuantity
from .combobox import QColormapComboBox # noqa: TCH004
from .spinbox._quantity import QQuantity # noqa: TCH004
def __getattr__(name: str) -> Any:

View File

@@ -4,7 +4,6 @@ from typing import TYPE_CHECKING, Container
from cmap import Colormap
from qtpy.QtCore import Qt, Signal
from qtpy.QtGui import QKeyEvent
from qtpy.QtWidgets import QComboBox, QCompleter, QWidget
from ._cmap_item_delegate import QColormapItemDelegate
@@ -13,6 +12,7 @@ from ._cmap_utils import try_cast_colormap
if TYPE_CHECKING:
from cmap._catalog import Category, Interpolation
from qtpy.QtGui import QKeyEvent
class CmapCatalogComboBox(QComboBox):

View File

@@ -1,14 +1,16 @@
from __future__ import annotations
from typing import cast
from typing import TYPE_CHECKING, cast
from cmap import Colormap
from qtpy.QtCore import QModelIndex, QObject, QPersistentModelIndex, QRect, QSize, Qt
from qtpy.QtGui import QColor, QPainter
from qtpy.QtWidgets import QStyle, QStyledItemDelegate, QStyleOptionViewItem
from ._cmap_utils import CMAP_ROLE, draw_colormap, pick_font_color, try_cast_colormap
if TYPE_CHECKING:
from cmap import Colormap
DEFAULT_SIZE = QSize(80, 22)
DEFAULT_BORDER_COLOR = QColor(Qt.GlobalColor.transparent)

View File

@@ -1,12 +1,16 @@
from __future__ import annotations
from cmap import Colormap
from typing import TYPE_CHECKING
from qtpy.QtCore import Qt
from qtpy.QtGui import QIcon, QPainter, QPaintEvent, QPalette
from qtpy.QtWidgets import QApplication, QLineEdit, QStyle, QWidget
from ._cmap_utils import draw_colormap, pick_font_color, try_cast_colormap
if TYPE_CHECKING:
from cmap import Colormap
MISSING = QStyle.StandardPixmap.SP_TitleBarContextHelpButton

View File

@@ -56,12 +56,14 @@ def draw_colormap(
from qtpy.QtWidgets import QWidget
from superqt.utils import draw_colormap
viridis = 'viridis' # or cmap.Colormap('viridis')
viridis = "viridis" # or cmap.Colormap('viridis')
class W(QWidget):
def paintEvent(self, event) -> None:
draw_colormap(self, viridis, event.rect())
# or draw onto a QPixmap
pm = QPixmap(200, 200)
draw_colormap(pm, viridis)

View File

@@ -1,4 +1,5 @@
"""A collapsible widget to hide and unhide child widgets."""
from __future__ import annotations
from qtpy.QtCore import (

View File

@@ -13,7 +13,7 @@ __all__ = (
if TYPE_CHECKING:
from superqt.cmap import QColormapComboBox
from superqt.cmap import QColormapComboBox # noqa: TCH004
def __getattr__(name: str) -> Any: # pragma: no cover

View File

@@ -104,7 +104,7 @@ def icon(
plugin is installed)
>>> btn = QPushButton()
>>> btn.setIcon(icon('fa5s.smile'))
>>> btn.setIcon(icon("fa5s.smile"))
can also directly import from fonticon_fa5
>>> from fonticon_fa5 import FA5S
@@ -130,7 +130,7 @@ def icon(
... "disabled": {
... "color": "green",
... "scale_factor": 0.8,
... "animation": spin(btn)
... "animation": spin(btn),
... },
... },
... )

View File

@@ -4,7 +4,7 @@ import warnings
from collections import abc, defaultdict
from dataclasses import dataclass
from pathlib import Path
from typing import ClassVar, DefaultDict, Sequence, Tuple, Union, cast
from typing import TYPE_CHECKING, ClassVar, DefaultDict, Sequence, Tuple, Union, cast
from qtpy import QT_VERSION
from qtpy.QtCore import QObject, QPoint, QRect, QSize, Qt
@@ -25,7 +25,8 @@ from typing_extensions import TypedDict
from superqt.utils import QMessageHandler
from ._animations import Animation
if TYPE_CHECKING:
from ._animations import Animation
class Unset:
@@ -157,9 +158,9 @@ class _QFontIconEngine(QIconEngine):
def __init__(self, options: _IconOptions):
super().__init__()
self._opts: defaultdict[
QIcon.State, dict[QIcon.Mode, _IconOptions | None]
] = DefaultDict(dict)
self._opts: defaultdict[QIcon.State, dict[QIcon.Mode, _IconOptions | None]] = (
DefaultDict(dict)
)
self._opts[QIcon.State.Off][QIcon.Mode.Normal] = options
self.update_hash()

View File

@@ -13,6 +13,8 @@ warnings.warn(
# forward any requests for superqt.qtcompat.* to qtpy.*
class SuperQtImporter(abc.MetaPathFinder):
"""Pseudo-importer to forward superqt.qtcompat.* to qtpy.*."""
def find_spec(self, fullname: str, path, target=None): # type: ignore
"""Forward any requests for superqt.qtcompat.* to qtpy.*."""
if fullname.startswith(__name__):

View File

@@ -19,6 +19,7 @@ So that's what `_GenericSlider` is below.
scalar (with one handle per item), and it forms the basis of
QRangeSlider.
"""
import os
import platform
from typing import TypeVar

View File

@@ -133,14 +133,12 @@ class QLabeledSlider(_SliderProxy, QAbstractSlider):
_slider: QSlider
@overload
def __init__(self, parent: QWidget | None = ...) -> None:
...
def __init__(self, parent: QWidget | None = ...) -> None: ...
@overload
def __init__(
self, orientation: Qt.Orientation, parent: QWidget | None = ...
) -> None:
...
) -> None: ...
def __init__(self, *args: Any, **kwargs: Any) -> None:
parent, orientation = _handle_overloaded_slider_sig(args, kwargs)
@@ -263,14 +261,12 @@ class QLabeledDoubleSlider(QLabeledSlider):
_frangeChanged = Signal(float, float)
@overload
def __init__(self, parent: QWidget | None = ...) -> None:
...
def __init__(self, parent: QWidget | None = ...) -> None: ...
@overload
def __init__(
self, orientation: Qt.Orientation, parent: QWidget | None = ...
) -> None:
...
) -> None: ...
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
@@ -300,14 +296,12 @@ class QLabeledRangeSlider(_SliderProxy, QAbstractSlider):
_slider: QRangeSlider
@overload
def __init__(self, parent: QWidget | None = ...) -> None:
...
def __init__(self, parent: QWidget | None = ...) -> None: ...
@overload
def __init__(
self, orientation: Qt.Orientation, parent: QWidget | None = ...
) -> None:
...
) -> None: ...
def __init__(self, *args: Any, **kwargs: Any) -> None:
parent, orientation = _handle_overloaded_slider_sig(args, kwargs)
@@ -545,14 +539,12 @@ class QLabeledDoubleRangeSlider(QLabeledRangeSlider):
_frangeChanged = Signal(float, float)
@overload
def __init__(self, parent: QWidget | None = ...) -> None:
...
def __init__(self, parent: QWidget | None = ...) -> None: ...
@overload
def __init__(
self, orientation: Qt.Orientation, parent: QWidget | None = ...
) -> None:
...
) -> None: ...
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)

View File

@@ -1,7 +1,7 @@
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from superqt.cmap import draw_colormap
from superqt.cmap import draw_colormap # noqa: TCH004
__all__ = (
"CodeSyntaxHighlight",

View File

@@ -68,8 +68,6 @@ def ensure_main_thread(
timeout: int = 1000,
) -> Callable[P, Future[R]]: ...
# fmt: on
def ensure_main_thread(
func: Callable | None = None, await_return: bool = False, timeout: int = 1000
):
@@ -132,8 +130,6 @@ def ensure_object_thread(
timeout: int = 1000,
) -> Callable[P, Future[R]]: ...
# fmt: on
def ensure_object_thread(
func: Callable | None = None, await_return: bool = False, timeout: int = 1000
):

View File

@@ -38,7 +38,7 @@ class QMessageHandler:
>>> logger = logging.getLogger(__name__)
>>> with QMessageHandler(logger): # re-reoute Qt messages to a python logger.
... ...
... ...
"""
_qt2loggertype: ClassVar[dict[QtMsgType, int]] = {

View File

@@ -23,16 +23,13 @@ if TYPE_CHECKING:
class SigInst(Generic[_T]):
@staticmethod
def connect(slot: Callable[[_T], Any], type: type | None = ...) -> None:
...
def connect(slot: Callable[[_T], Any], type: type | None = ...) -> None: ...
@staticmethod
def disconnect(slot: Callable[[_T], Any] = ...) -> None:
...
def disconnect(slot: Callable[[_T], Any] = ...) -> None: ...
@staticmethod
def emit(*args: _T) -> None:
...
def emit(*args: _T) -> None: ...
from typing_extensions import Literal, ParamSpec
@@ -52,7 +49,7 @@ _R = TypeVar("_R")
def as_generator_function(
func: Callable[_P, _R]
func: Callable[_P, _R],
) -> Callable[_P, Generator[None, None, _R]]:
"""Turns a regular function (single return) into a generator function."""
@@ -211,7 +208,6 @@ class WorkerBase(QRunnable, Generic[_R]):
--------
```python
class MyWorker(WorkerBase):
def work(self):
i = 0
while True:
@@ -499,8 +495,7 @@ def create_worker(
_worker_class: type[GeneratorWorker] | type[FunctionWorker] | None = None,
_ignore_errors: bool = False,
**kwargs,
) -> GeneratorWorker[_Y, _S, _R]:
...
) -> GeneratorWorker[_Y, _S, _R]: ...
@overload
@@ -512,8 +507,7 @@ def create_worker(
_worker_class: type[GeneratorWorker] | type[FunctionWorker] | None = None,
_ignore_errors: bool = False,
**kwargs,
) -> FunctionWorker[_R]:
...
) -> FunctionWorker[_R]: ...
def create_worker(
@@ -574,8 +568,10 @@ def create_worker(
```python
def long_function(duration):
import time
time.sleep(duration)
worker = create_worker(long_function, 10)
```
"""
@@ -630,8 +626,7 @@ def thread_worker(
connect: dict[str, Callable | Sequence[Callable]] | None = None,
worker_class: type[WorkerBase] | None = None,
ignore_errors: bool = False,
) -> Callable[_P, GeneratorWorker[_Y, _S, _R]]:
...
) -> Callable[_P, GeneratorWorker[_Y, _S, _R]]: ...
@overload
@@ -641,8 +636,7 @@ def thread_worker(
connect: dict[str, Callable | Sequence[Callable]] | None = None,
worker_class: type[WorkerBase] | None = None,
ignore_errors: bool = False,
) -> Callable[_P, FunctionWorker[_R]]:
...
) -> Callable[_P, FunctionWorker[_R]]: ...
@overload
@@ -652,8 +646,7 @@ def thread_worker(
connect: dict[str, Callable | Sequence[Callable]] | None = None,
worker_class: type[WorkerBase] | None = None,
ignore_errors: bool = False,
) -> Callable[[Callable], Callable[_P, FunctionWorker | GeneratorWorker]]:
...
) -> Callable[[Callable], Callable[_P, FunctionWorker | GeneratorWorker]]: ...
def thread_worker(
@@ -737,7 +730,8 @@ def thread_worker(
yield i
# do teardown
return 'anything'
return "anything"
# call the function to start running in another thread.
worker = long_function()
@@ -790,8 +784,7 @@ if TYPE_CHECKING:
class WorkerProtocol(QObject):
finished: Signal
def work(self) -> None:
...
def work(self) -> None: ...
def new_worker_qthread(
@@ -846,9 +839,7 @@ def new_worker_qthread(
Create some QObject that has a long-running work method:
```python
class Worker(QObject):
finished = Signal()
increment = Signal(int)
@@ -860,16 +851,18 @@ def new_worker_qthread(
def work(self):
# some long running task...
import time
for i in range(10):
time.sleep(1)
self.increment.emit(i)
self.finished.emit()
worker, thread = new_worker_qthread(
Worker,
'argument',
"argument",
_start_thread=True,
_connect={'increment': print},
_connect={"increment": print},
)
```
"""

View File

@@ -26,6 +26,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
from __future__ import annotations
from concurrent.futures import Future
@@ -301,8 +302,7 @@ def qthrottled(
leading: bool = True,
timer_type: Qt.TimerType = Qt.TimerType.PreciseTimer,
parent: QObject | None = None,
) -> ThrottledCallable[P, R]:
...
) -> ThrottledCallable[P, R]: ...
@overload
@@ -312,8 +312,7 @@ def qthrottled(
leading: bool = True,
timer_type: Qt.TimerType = Qt.TimerType.PreciseTimer,
parent: QObject | None = None,
) -> Callable[[Callable[P, R]], ThrottledCallable[P, R]]:
...
) -> Callable[[Callable[P, R]], ThrottledCallable[P, R]]: ...
def qthrottled(
@@ -364,8 +363,7 @@ def qdebounced(
leading: bool = False,
timer_type: Qt.TimerType = Qt.TimerType.PreciseTimer,
parent: QObject | None = None,
) -> ThrottledCallable[P, R]:
...
) -> ThrottledCallable[P, R]: ...
@overload
@@ -375,8 +373,7 @@ def qdebounced(
leading: bool = False,
timer_type: Qt.TimerType = Qt.TimerType.PreciseTimer,
parent: QObject | None = None,
) -> Callable[[Callable[P, R]], ThrottledCallable[P, R]]:
...
) -> Callable[[Callable[P, R]], ThrottledCallable[P, R]]: ...
def qdebounced(