diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9c21e9bb..251538ca 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,16 +1,4 @@
repos:
- - repo: https://github.com/psf/black
- rev: 24.10.0
- hooks:
- - id: black
- args: ["--config=pyproject.toml"]
-
- - repo: https://github.com/pycqa/isort
- rev: 5.13.2
- hooks:
- - id: isort
- args: ["--check", "--settings=.isort.cfg"]
-
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.13.0
hooks:
@@ -26,30 +14,12 @@ repos:
pass_filenames: false
args: ["--config-file", "mypy.ini", "@mypy_checklist.txt"]
- - repo: https://github.com/PyCQA/flake8
- rev: 7.1.1
- hooks:
- - id: flake8
- additional_dependencies:
- ["flake8-black==0.3.6", "flake8-isort==6.1.1", "flake8-quotes==3.3.2"]
- args: ["--config=.flake8"]
-
- repo: https://github.com/codespell-project/codespell
rev: v2.3.0
hooks:
- id: codespell
args: ["docs examples examples_flask pyvista tests", "*.py *.rst *.md"]
- - repo: https://github.com/pycqa/pydocstyle
- rev: 6.3.0
- hooks:
- - id: pydocstyle
- additional_dependencies: [toml==0.10.2]
- # We use the 'match' and do not want pre-commit to pass
- # globbed files
- pass_filenames: false
- args: ["--config=pyproject.toml"]
-
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
@@ -64,30 +34,15 @@ repos:
hooks:
- id: check-github-workflows
- - repo: local
- hooks:
- - id: pylint
- name: pylint
- entry: pylint
- language: system
- types: [python]
- args: [
- "-rn", # Only display messages
- "-sn", # Don't display the score
- "--rcfile=.pylintrc", # Specify rc file
- ]
- - id: pycodestyle
- name: pycodestyle
- entry: pycodestyle
- language: system
- types: [python]
- args: ["--config=./\\.pycodestyle"]
-
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v4.0.0-alpha.8"
hooks:
- id: prettier
types_or: [yaml, markdown, html, css, scss, javascript, json]
-ci:
- skip: [pylint, pycodestyle]
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.6.9
+ hooks:
+ - id: ruff
+ args: [--fix, --show-fixes]
+ - id: ruff-format
diff --git a/docs/conf.py b/docs/conf.py
index c8f3ff90..bd3491c9 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,27 +1,29 @@
+from __future__ import annotations # noqa: INP001, D100
+
import datetime
+import faulthandler
import os
import sys
-if sys.version_info >= (3, 0):
- import faulthandler
- faulthandler.enable()
+faulthandler.enable()
+
+sys.path.insert(0, os.path.abspath(".")) # noqa: PTH100
-sys.path.insert(0, os.path.abspath('.'))
+import numpy as np # noqa: E402
-import numpy as np
# -- pyvista configuration ---------------------------------------------------
-import pyvista
+import pyvista # noqa: E402
-import pyvistaqt
+import pyvistaqt # noqa: E402
# Manage errors
-pyvista.set_error_output_file('errors.txt')
+pyvista.set_error_output_file("errors.txt")
# Ensure that offscreen rendering is used for docs generation
-pyvista.OFF_SCREEN = True # Not necessary - simply an insurance policy
+pyvista.OFF_SCREEN = True # Not necessary - simply an insurance policy
pyvista.BUILDING_GALLERY = True
# Preferred plotting style for documentation
-pyvista.set_plot_theme('document')
+pyvista.set_plot_theme("document")
ws = np.array([1024, 768]) * 2
try:
pyvista.global_theme.window_size = ws
@@ -29,56 +31,57 @@
rc = pyvista.rcParams["window_size"] = ws
del ws
# Save figures in specified directory
-pyvista.FIGURE_PATH = os.path.join(os.path.abspath('./images/'), 'auto-generated/')
-if not os.path.exists(pyvista.FIGURE_PATH):
- os.makedirs(pyvista.FIGURE_PATH)
+pyvista.FIGURE_PATH = os.path.join(os.path.abspath("./images/"), "auto-generated/") # noqa: PTH100, PTH118
+if not os.path.exists(pyvista.FIGURE_PATH): # noqa: PTH110
+ os.makedirs(pyvista.FIGURE_PATH) # noqa: PTH103
# SG warnings
-import warnings
+import warnings # noqa: E402
warnings.filterwarnings(
"ignore",
category=UserWarning,
- message='Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.',
+ message="Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.",
)
# -- General configuration ------------------------------------------------
numfig = False
html_show_sourcelink = False
-html_logo = './_static/pyvista_logo.png'
+html_logo = "./_static/pyvista_logo.png"
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
-extensions = ['sphinx.ext.autodoc',
- 'sphinx.ext.napoleon',
- 'sphinx.ext.doctest',
- 'sphinx.ext.autosummary',
- 'notfound.extension',
- 'sphinx_copybutton',
- 'sphinx.ext.extlinks',
- 'sphinx.ext.coverage',
- 'sphinx.ext.intersphinx',
- ]
+extensions = [
+ "sphinx.ext.autodoc",
+ "sphinx.ext.napoleon",
+ "sphinx.ext.doctest",
+ "sphinx.ext.autosummary",
+ "notfound.extension",
+ "sphinx_copybutton",
+ "sphinx.ext.extlinks",
+ "sphinx.ext.coverage",
+ "sphinx.ext.intersphinx",
+]
linkcheck_retries = 3
linkcheck_timeout = 500
# Add any paths that contain templates here, relative to this directory.
-templates_path = ['_templates']
+templates_path = ["_templates"]
# The suffix(es) of source filenames.
-source_suffix = '.rst'
+source_suffix = ".rst"
# The master toctree document.
-master_doc = 'index'
+master_doc = "index"
# General information about the project.
-project = u'PyVistaQt'
-year = datetime.date.today().year
-copyright = u'2017-{}, The PyVista Developers'.format(year)
-author = u'Alex Kaszynski and Bane Sullivan'
+project = "PyVistaQt"
+year = datetime.date.today().year # noqa: DTZ011
+copyright = f"2017-{year}, The PyVista Developers" # noqa: A001
+author = "Alex Kaszynski and Bane Sullivan"
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -95,29 +98,28 @@
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
-language = 'en'
+language = "en"
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
-exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', '**.ipynb_checkpoints']
+exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "**.ipynb_checkpoints"]
# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'friendly'
+pygments_style = "friendly"
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Sphinx Gallery Options
-# from sphinx_gallery.sorting import FileNameSortKey
+# from sphinx_gallery.sorting import FileNameSortKey # noqa: ERA001
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-import pydata_sphinx_theme
html_theme = "pydata_sphinx_theme"
html_context = {
@@ -133,21 +135,21 @@
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
html_show_sphinx = False
-html_theme = 'pydata_sphinx_theme'
+html_theme = "pydata_sphinx_theme"
html_context = {
# Enable the "Edit in GitHub link within the header of each page.
- 'display_github': False,
+ "display_github": False,
# Set the following variables to generate the resulting github URL for each page.
- # Format Template: https://{{ github_host|default("github.com") }}/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }}
- 'github_user': 'pyvista',
- 'github_repo': 'pyvistaqt',
- 'github_version': 'main/docs/',
- 'menu_links_name': 'Getting Connected',
- 'menu_links': [
- (' Slack Community', 'http://slack.pyvista.org'),
- (' Support', 'https://github.com/pyvista/pyvista-support'),
- (' Source Code', 'https://github.com/pyvista/pyvistaqt'),
- (' Contributing', 'https://github.com/pyvista/pyvistaqt/blob/main/CONTRIBUTING.md'),
+ # Format Template: https://{{ github_host|default("github.com") }}/{{ github_user }}/{{ github_repo }}/blob/{{ github_version }}{{ conf_py_path }}{{ pagename }}{{ suffix }} # noqa: E501
+ "github_user": "pyvista",
+ "github_repo": "pyvistaqt",
+ "github_version": "main/docs/",
+ "menu_links_name": "Getting Connected",
+ "menu_links": [
+ (' Slack Community', "http://slack.pyvista.org"),
+ (' Support', "https://github.com/pyvista/pyvista-support"),
+ (' Source Code', "https://github.com/pyvista/pyvistaqt"),
+ (' Contributing', "https://github.com/pyvista/pyvistaqt/blob/main/CONTRIBUTING.md"),
],
}
@@ -183,19 +185,19 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+html_static_path = ["_static"]
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
-htmlhelp_basename = 'pyvistaqtdoc'
+htmlhelp_basename = "pyvistaqtdoc"
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {
"python": ("https://docs.python.org/3/", None),
- "pyvista": ('https://docs.pyvista.org/', None),
+ "pyvista": ("https://docs.pyvista.org/", None),
"PySide6": ("https://doc.qt.io/qtforpython-6/", None),
"PyQt6": ("https://www.riverbankcomputing.com/static/Docs/PyQt6/", None),
"numpy": ("https://numpy.org/doc/stable", None),
@@ -221,61 +223,63 @@
# -- Custom 404 page
notfound_context = {
- 'body': '
Page not found.
\n\nPerhaps try the examples page.',
+ "body": 'Page not found.
\n\nPerhaps try the examples page.',
}
notfound_no_urls_prefix = True
-from docutils.parsers.rst import directives
-# -- Autosummary options
-from sphinx.ext.autosummary import Autosummary, get_documenter
-from sphinx.util.inspect import safe_getattr
+from docutils.parsers.rst import directives # noqa: E402
+# -- Autosummary options
+from sphinx.ext.autosummary import Autosummary # noqa: E402
+from sphinx.ext.autosummary import get_documenter # noqa: E402
+from sphinx.util.inspect import safe_getattr # noqa: E402
-class AutoAutoSummary(Autosummary):
- option_spec = {
- 'methods': directives.unchanged,
- 'attributes': directives.unchanged,
+class AutoAutoSummary(Autosummary): # noqa: D101
+ option_spec = { # noqa: RUF012
+ "methods": directives.unchanged,
+ "attributes": directives.unchanged,
}
required_arguments = 1
app = None
@staticmethod
- def get_members(obj, typ, include_public=None):
+ def get_members(obj, typ, include_public=None): # noqa: ANN001, ANN205, D102
if not include_public:
include_public = []
items = []
- for name in sorted(obj.__dict__.keys()):#dir(obj):
+ for name in sorted(obj.__dict__.keys()): # dir(obj):
try:
documenter = get_documenter(AutoAutoSummary.app, safe_getattr(obj, name), obj)
except AttributeError:
continue
if documenter.objtype in typ:
items.append(name)
- public = [x for x in items if x in include_public or not x.startswith('_')]
+ public = [x for x in items if x in include_public or not x.startswith("_")]
return public, items
- def run(self):
+ def run(self): # noqa: ANN201, D102
clazz = str(self.arguments[0])
try:
- (module_name, class_name) = clazz.rsplit('.', 1)
+ (module_name, class_name) = clazz.rsplit(".", 1)
m = __import__(module_name, globals(), locals(), [class_name])
c = getattr(m, class_name)
- if 'methods' in self.options:
- _, methods = self.get_members(c, ['method'], ['__init__'])
- self.content = ["~%s.%s" % (clazz, method) for method in methods if not method.startswith('_')]
- if 'attributes' in self.options:
- _, attribs = self.get_members(c, ['attribute', 'property'])
- self.content = ["~%s.%s" % (clazz, attrib) for attrib in attribs if not attrib.startswith('_')]
- except:
- print('Something went wrong when autodocumenting {}'.format(clazz))
+ if "methods" in self.options:
+ _, methods = self.get_members(c, ["method"], ["__init__"])
+ self.content = [f"~{clazz}.{method}" for method in methods if not method.startswith("_")]
+ if "attributes" in self.options:
+ _, attribs = self.get_members(c, ["attribute", "property"])
+ self.content = [f"~{clazz}.{attrib}" for attrib in attribs if not attrib.startswith("_")]
+ except: # noqa: S110, E722
+ pass
finally:
- return super(AutoAutoSummary, self).run()
+ return super().run() # noqa: B012
+
-def setup(app):
+def setup(app) -> None: # noqa: ANN001, D103
AutoAutoSummary.app = app
- app.add_directive('autoautosummary', AutoAutoSummary)
+ app.add_directive("autoautosummary", AutoAutoSummary)
app.add_css_file("style.css")
app.add_css_file("copybutton.css")
diff --git a/pyproject.toml b/pyproject.toml
index fcc8a4c1..0826ba20 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -25,4 +25,35 @@ match = '''
| rwi
).*\.py
)
-'''
\ No newline at end of file
+'''
+
+[tool.ruff]
+line-length = 150
+
+[tool.ruff.format]
+docstring-code-format = true
+
+[tool.ruff.lint]
+select = ["ALL"]
+ignore = [
+ "COM812",
+ "D203",
+ "D212",
+ "ISC001"
+]
+
+[tool.ruff.lint.isort]
+# Sort by name, don't cluster "from" vs "import"
+force-sort-within-sections = true
+# Combines "as" imports on the same line
+combine-as-imports = true
+required-imports = ["from __future__ import annotations"]
+force-single-line = true
+
+[tool.ruff.lint.per-file-ignores]
+"doc/**" = ["INP001"]
+"tests/**" = ["ANN001", "INP001", "S101"]
+
+[tool.ruff.lint.pyupgrade]
+# Preserve types, even if a file imports `from __future__ import annotations`.
+keep-runtime-typing = true
diff --git a/pyvistaqt/__init__.py b/pyvistaqt/__init__.py
index cdc9bb43..600f9c5f 100755
--- a/pyvistaqt/__init__.py
+++ b/pyvistaqt/__init__.py
@@ -1,43 +1,49 @@
-"""PyVista package for 3D plotting and mesh analysis."""
+"""PyVista package for 3D plotting and mesh analysis.""" # noqa: EXE002
+
+from __future__ import annotations
try:
from importlib.metadata import version
__version__ = version("pyvistaqt")
-except Exception: # pragma: no cover # pylint: disable=broad-exception-caught
+except Exception: # pragma: no cover # pylint: disable=broad-exception-caught # noqa: BLE001
try:
from ._version import __version__
except ImportError:
- __version__ = '0.0.0'
+ __version__ = "0.0.0"
try:
- from qtpy import QtCore # noqa
-except Exception as exc: # pragma: no cover # pylint: disable=broad-except
+ from qtpy import QtCore # noqa: F401
+except Exception as exc: # pragma: no cover # pylint: disable=broad-except # noqa: BLE001
_exc_msg = exc
# pylint: disable=too-few-public-methods
class _QtBindingError:
- def __init__(self, *args, **kwargs):
- raise RuntimeError(f"No Qt binding was found, got: {_exc_msg}")
+ def __init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003, ARG002
+ msg = f"No Qt binding was found, got: {_exc_msg}"
+ raise RuntimeError(msg)
# pylint: disable=too-few-public-methods
- class BackgroundPlotter(_QtBindingError):
+ class BackgroundPlotter(_QtBindingError): # noqa: N818
"""Handle Qt binding error for BackgroundPlotter."""
# pylint: disable=too-few-public-methods
- class MainWindow(_QtBindingError):
+ class MainWindow(_QtBindingError): # noqa: N818
"""Handle Qt binding error for MainWindow."""
# pylint: disable=too-few-public-methods
- class MultiPlotter(_QtBindingError):
+ class MultiPlotter(_QtBindingError): # noqa: N818
"""Handle Qt binding error for MultiPlotter."""
# pylint: disable=too-few-public-methods
- class QtInteractor(_QtBindingError):
+ class QtInteractor(_QtBindingError): # noqa: N818
"""Handle Qt binding error for QtInteractor."""
else:
- from .plotting import BackgroundPlotter, MainWindow, MultiPlotter, QtInteractor
+ from .plotting import BackgroundPlotter
+ from .plotting import MainWindow
+ from .plotting import MultiPlotter
+ from .plotting import QtInteractor
__all__ = [
diff --git a/pyvistaqt/counter.py b/pyvistaqt/counter.py
index e31a7a64..943f5225 100644
--- a/pyvistaqt/counter.py
+++ b/pyvistaqt/counter.py
@@ -1,6 +1,10 @@
-"""This module contains a basic Qt-compatible counter class."""
+"""This module contains a basic Qt-compatible counter class.""" # noqa: D404
-from qtpy.QtCore import QObject, Signal, Slot
+from __future__ import annotations
+
+from qtpy.QtCore import QObject
+from qtpy.QtCore import Signal
+from qtpy.QtCore import Slot
class Counter(QObject):
@@ -16,11 +20,11 @@ def __init__(self, count: int) -> None:
if isinstance(count, int) and count > 0:
self.count = count
elif count > 0:
- raise TypeError(
- f"Expected type of `count` to be `int` but got: {type(count)}"
- )
+ msg = f"Expected type of `count` to be `int` but got: {type(count)}"
+ raise TypeError(msg)
else:
- raise ValueError("count is not strictly positive.")
+ msg = "count is not strictly positive."
+ raise ValueError(msg)
@Slot()
def decrease(self) -> None:
diff --git a/pyvistaqt/dialog.py b/pyvistaqt/dialog.py
index 0eaa3612..7228e553 100644
--- a/pyvistaqt/dialog.py
+++ b/pyvistaqt/dialog.py
@@ -1,26 +1,32 @@
-"""This module contains Qt dialog widgets."""
+"""This module contains Qt dialog widgets.""" # noqa: D404
+
+from __future__ import annotations
import os
-from typing import Any, List
+from typing import TYPE_CHECKING
+from typing import Any
+from typing import List
+from typing import Optional
-import numpy as np # type: ignore
-import pyvista as pv
from qtpy import QtCore
from qtpy.QtCore import Signal
-from qtpy.QtWidgets import (
- QDialog,
- QDoubleSpinBox,
- QFileDialog,
- QFormLayout,
- QHBoxLayout,
- QSlider,
-)
+from qtpy.QtWidgets import QDialog
+from qtpy.QtWidgets import QDoubleSpinBox
+from qtpy.QtWidgets import QFileDialog
+from qtpy.QtWidgets import QFormLayout
+from qtpy.QtWidgets import QHBoxLayout
+from qtpy.QtWidgets import QSlider
+
+if TYPE_CHECKING:
+ import numpy as np
+ import pyvista as pv
-from .window import MainWindow
+ from .window import MainWindow
class FileDialog(QFileDialog):
- """Generic file query.
+ """
+ Generic file query.
It emits a signal when a file is selected and
the dialog was property closed.
@@ -31,14 +37,14 @@ class FileDialog(QFileDialog):
dlg_accepted = Signal(str)
# pylint: disable=too-many-arguments
- def __init__(
+ def __init__( # noqa: PLR0913
self,
parent: MainWindow = None,
- filefilter: List[str] = None,
- save_mode: bool = True,
- show: bool = True,
+ filefilter: Optional[List[str]] = None,
+ save_mode: bool = True, # noqa: FBT001, FBT002
+ show: bool = True, # noqa: FBT001, FBT002
callback: np.ndarray = None,
- directory: bool = False,
+ directory: bool = False, # noqa: FBT001, FBT002
) -> None:
"""Initialize the file dialog."""
super().__init__(parent)
@@ -51,7 +57,7 @@ def __init__(
if directory:
self.FileMode(QFileDialog.Directory)
- self.setOption(QFileDialog.ShowDirsOnly, True)
+ self.setOption(QFileDialog.ShowDirsOnly, True) # noqa: FBT003
if save_mode:
self.setAcceptMode(QFileDialog.AcceptSave)
@@ -63,7 +69,8 @@ def __init__(
self.show()
def emit_accepted(self) -> None:
- """Send signal that the file dialog was closed properly.
+ """
+ Send signal that the file dialog was closed properly.
Sends:
filename
@@ -71,19 +78,20 @@ def emit_accepted(self) -> None:
"""
if self.result():
filename = self.selectedFiles()[0]
- if os.path.isdir(os.path.dirname(filename)):
+ if os.path.isdir(os.path.dirname(filename)): # noqa: PTH112, PTH120
self.dlg_accepted.emit(filename)
class DoubleSlider(QSlider):
- """Double precision slider.
+ """
+ Double precision slider.
Reference:
https://gist.github.com/dennis-tra/994a65d6165a328d4eabaadbaedac2cc
"""
- def __init__(self, *args: Any, **kwargs: Any) -> None:
+ def __init__(self, *args: Any, **kwargs: Any) -> None: # noqa: ANN401
"""Initialize the double slider."""
super().__init__(*args, **kwargs)
self.decimals = 5
@@ -102,28 +110,26 @@ def _value_range(self) -> float:
def value(self) -> float:
"""Return the value of the slider."""
- return (
- float(super().value()) / self._max_int * self._value_range + self._min_value
- )
+ return float(super().value()) / self._max_int * self._value_range + self._min_value
- def setValue(self, value: float) -> None: # pylint: disable=invalid-name
+ def setValue(self, value: float) -> None: # pylint: disable=invalid-name # noqa: N802
"""Set the value of the slider."""
- super().setValue(
- int((value - self._min_value) / self._value_range * self._max_int)
- )
+ super().setValue(int((value - self._min_value) / self._value_range * self._max_int))
- def setMinimum(self, value: float) -> None: # pylint: disable=invalid-name
+ def setMinimum(self, value: float) -> None: # pylint: disable=invalid-name # noqa: N802
"""Set the minimum value of the slider."""
if value > self._max_value: # pragma: no cover
- raise ValueError("Minimum limit cannot be higher than maximum")
+ msg = "Minimum limit cannot be higher than maximum"
+ raise ValueError(msg)
self._min_value = value
self.setValue(self.value())
- def setMaximum(self, value: float) -> None: # pylint: disable=invalid-name
+ def setMaximum(self, value: float) -> None: # pylint: disable=invalid-name # noqa: N802
"""Set the maximum value of the slider."""
if value < self._min_value: # pragma: no cover
- raise ValueError("Minimum limit cannot be higher than maximum")
+ msg = "Minimum limit cannot be higher than maximum"
+ raise ValueError(msg)
self._max_value = value
self.setValue(self.value())
@@ -138,7 +144,7 @@ class RangeGroup(QHBoxLayout):
def __init__(
self,
parent: MainWindow,
- callback: Any,
+ callback: Any, # noqa: ANN401
minimum: float = 0.0,
maximum: float = 20.0,
value: float = 1.0,
@@ -153,9 +159,7 @@ def __init__(
self.minimum = minimum
self.maximum = maximum
- self.spinbox = QDoubleSpinBox(
- value=value, minimum=minimum, maximum=maximum, decimals=4
- )
+ self.spinbox = QDoubleSpinBox(value=value, minimum=minimum, maximum=maximum, decimals=4)
self.addWidget(self.slider)
self.addWidget(self.spinbox)
@@ -165,22 +169,20 @@ def __init__(
self.spinbox.valueChanged.connect(self.update_value)
self.spinbox.valueChanged.connect(callback)
- return None
-
- def update_spinbox(self, value: float) -> None: # pylint: disable=unused-argument
+ def update_spinbox(self, value: float) -> None: # pylint: disable=unused-argument # noqa: ARG002
"""Set the value of the internal spinbox."""
self.spinbox.setValue(self.slider.value())
- def update_value(self, value: float) -> None: # pylint: disable=unused-argument
+ def update_value(self, value: float) -> None: # pylint: disable=unused-argument # noqa: ARG002
"""Update the value of the internal slider."""
# if self.spinbox.value() < self.minimum:
- # self.spinbox.setValue(self.minimum)
- # elif self.spinbox.value() > self.maximum:
- # self.spinbox.setValue(self.maximum)
+ # self.spinbox.setValue(self.minimum) # noqa: ERA001
+ # elif self.spinbox.value() > self.maximum: # noqa: ERA001
+ # self.spinbox.setValue(self.maximum) # noqa: ERA001
- self.slider.blockSignals(True)
+ self.slider.blockSignals(True) # noqa: FBT003
self.slider.setValue(self.spinbox.value())
- self.slider.blockSignals(False)
+ self.slider.blockSignals(False) # noqa: FBT003
@property
def value(self) -> float:
@@ -201,9 +203,7 @@ class ScaleAxesDialog(QDialog):
accepted = Signal(float)
signal_close = Signal()
- def __init__(
- self, parent: MainWindow, plotter: pv.Plotter, show: bool = True
- ) -> None:
+ def __init__(self, parent: MainWindow, plotter: pv.Plotter, show: bool = True) -> None: # noqa: FBT001, FBT002
"""Initialize the scaling dialog."""
super().__init__(parent)
self.setGeometry(300, 300, 50, 50)
@@ -212,15 +212,9 @@ def __init__(
self.plotter = plotter
self.plotter.app_window.signal_close.connect(self.close)
- self.x_slider_group = RangeGroup(
- parent, self.update_scale, value=plotter.scale[0]
- )
- self.y_slider_group = RangeGroup(
- parent, self.update_scale, value=plotter.scale[1]
- )
- self.z_slider_group = RangeGroup(
- parent, self.update_scale, value=plotter.scale[2]
- )
+ self.x_slider_group = RangeGroup(parent, self.update_scale, value=plotter.scale[0])
+ self.y_slider_group = RangeGroup(parent, self.update_scale, value=plotter.scale[1])
+ self.z_slider_group = RangeGroup(parent, self.update_scale, value=plotter.scale[2])
form_layout = QFormLayout(self)
form_layout.addRow("X Scale", self.x_slider_group)
diff --git a/pyvistaqt/editor.py b/pyvistaqt/editor.py
index 4bd24e36..5ffa0cf6 100644
--- a/pyvistaqt/editor.py
+++ b/pyvistaqt/editor.py
@@ -1,25 +1,28 @@
-"""This module contains the Qt scene editor."""
+"""This module contains the Qt scene editor.""" # noqa: D404
-import weakref
+from __future__ import annotations
+
+from typing import TYPE_CHECKING
from typing import List
+import weakref
-from pyvista import Renderer
from qtpy.QtCore import Qt
-from qtpy.QtWidgets import (
- QCheckBox,
- QDialog,
- QDoubleSpinBox,
- QHBoxLayout,
- QLabel,
- QStackedWidget,
- QTreeWidget,
- QTreeWidgetItem,
- QVBoxLayout,
- QWidget,
-)
-from vtkmodules.vtkRenderingCore import vtkActor
-
-from .window import MainWindow
+from qtpy.QtWidgets import QCheckBox
+from qtpy.QtWidgets import QDialog
+from qtpy.QtWidgets import QDoubleSpinBox
+from qtpy.QtWidgets import QHBoxLayout
+from qtpy.QtWidgets import QLabel
+from qtpy.QtWidgets import QStackedWidget
+from qtpy.QtWidgets import QTreeWidget
+from qtpy.QtWidgets import QTreeWidgetItem
+from qtpy.QtWidgets import QVBoxLayout
+from qtpy.QtWidgets import QWidget
+
+if TYPE_CHECKING:
+ from pyvista import Renderer
+ from vtkmodules.vtkRenderingCore import vtkActor
+
+ from .window import MainWindow
class Editor(QDialog):
@@ -60,7 +63,7 @@ def update(self) -> None:
"""Update the internal widget list."""
self.tree_widget.clear()
for idx, renderer in enumerate(self.renderers):
- actors = renderer._actors # pylint: disable=protected-access
+ actors = renderer._actors # pylint: disable=protected-access # noqa: SLF001
widget_idx = self.stacked_widget.addWidget(_get_renderer_widget(renderer))
top_item = QTreeWidgetItem(self.tree_widget, [f"Renderer {idx}"])
top_item.setData(0, Qt.ItemDataRole.UserRole, widget_idx)
@@ -95,7 +98,7 @@ def _get_renderer_widget(renderer: Renderer) -> QWidget:
del renderer
# axes
- def _axes_callback(state: bool) -> None:
+ def _axes_callback(state: bool) -> None: # noqa: FBT001
renderer = renderer_ref()
if renderer is None or renderer.parent.iren is None: # pragma: no cover
return
@@ -120,7 +123,7 @@ def _get_actor_widget(actor: vtkActor) -> QWidget:
# visibility
set_vis_ref = weakref.ref(actor.SetVisibility)
- def _set_vis(visibility: bool) -> None: # pragma: no cover
+ def _set_vis(visibility: bool) -> None: # pragma: no cover # noqa: FBT001
set_vis = set_vis_ref()
if set_vis is not None:
set_vis(visibility)
diff --git a/pyvistaqt/plotting.py b/pyvistaqt/plotting.py
index 7ceb849b..8fffc06c 100644
--- a/pyvistaqt/plotting.py
+++ b/pyvistaqt/plotting.py
@@ -38,17 +38,28 @@
probably entirely separate from the Python ``super()`` process.
We fix this by internally by temporarily monkey-patching
``BasePlotter.__init__`` with a no-op ``__init__``.
-"""
+""" # noqa: D404
+
+from __future__ import annotations
+
import contextlib
+from functools import wraps
import logging
import os
import platform
import time
+from typing import Any
+from typing import Callable
+from typing import Dict
+from typing import Generator
+from typing import List
+from typing import Optional
+from typing import Tuple
+from typing import Type
+from typing import Union
import warnings
-from functools import wraps
-from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Type, Union
-import numpy as np # type: ignore
+import numpy as np # type: ignore # noqa: PGH003
import pyvista
from pyvista import global_theme
@@ -59,35 +70,37 @@
from pyvista.plotting.render_window_interactor import RenderWindowInteractor
try:
- from pyvista.core.utilities import conditional_decorator, threaded
+ from pyvista.core.utilities import conditional_decorator
+ from pyvista.core.utilities import threaded
except ImportError: # PV < 0.40
- from pyvista.utilities import conditional_decorator, threaded
-from qtpy import QtCore, QtGui
-from qtpy.QtCore import QSize, QTimer, Signal
-from qtpy.QtWidgets import (
- QAction,
- QApplication,
- QFrame,
- QGestureEvent,
- QGridLayout,
- QMenuBar,
- QToolBar,
- QVBoxLayout,
- QWidget,
-)
+ from pyvista.utilities import conditional_decorator
+ from pyvista.utilities import threaded
+from qtpy import QtCore
+from qtpy import QtGui
+from qtpy.QtCore import QSize
+from qtpy.QtCore import QTimer
+from qtpy.QtCore import Signal
+from qtpy.QtWidgets import QAction
+from qtpy.QtWidgets import QApplication
+from qtpy.QtWidgets import QFrame
+from qtpy.QtWidgets import QGestureEvent
+from qtpy.QtWidgets import QGridLayout
+from qtpy.QtWidgets import QMenuBar
+from qtpy.QtWidgets import QToolBar
+from qtpy.QtWidgets import QVBoxLayout
+from qtpy.QtWidgets import QWidget
from vtkmodules.vtkRenderingUI import vtkGenericRenderWindowInteractor
from .counter import Counter
-from .dialog import FileDialog, ScaleAxesDialog
+from .dialog import FileDialog
+from .dialog import ScaleAxesDialog
from .editor import Editor
from .rwi import QVTKRenderWindowInteractor
-from .utils import (
- _check_type,
- _create_menu_bar,
- _setup_application,
- _setup_ipython,
- _setup_off_screen,
-)
+from .utils import _check_type
+from .utils import _create_menu_bar
+from .utils import _setup_application
+from .utils import _setup_ipython
+from .utils import _setup_off_screen
from .window import MainWindow
LOG = logging.getLogger("pyvistaqt")
@@ -102,8 +115,8 @@
# See https://github.com/pyvista/pyvista/pull/693
# LOG is unused at the moment
-# LOG = logging.getLogger(__name__)
-# LOG.setLevel('DEBUG')
+# LOG = logging.getLogger(__name__) # noqa: ERA001
+# LOG.setLevel('DEBUG') # noqa: ERA001
SAVE_CAM_BUTTON_TEXT = "Save Camera"
CLEAR_CAMS_BUTTON_TEXT = "Clear Cameras"
@@ -137,7 +150,7 @@ def pad_image(arr: np.ndarray, max_size: int = 400) -> np.ndarray:
@contextlib.contextmanager
def _no_base_plotter_init() -> Generator[None, None, None]:
init = BasePlotter.__init__
- BasePlotter.__init__ = lambda *args, **kwargs: None
+ BasePlotter.__init__ = lambda *args, **kwargs: None # noqa: ARG005
try:
yield
finally:
@@ -145,7 +158,8 @@ def _no_base_plotter_init() -> Generator[None, None, None]:
class QtInteractor(QVTKRenderWindowInteractor, BasePlotter):
- """Extend QVTKRenderWindowInteractor class.
+ """
+ Extend QVTKRenderWindowInteractor class.
This adds the methods available to pyvista.Plotter.
@@ -175,6 +189,7 @@ class QtInteractor(QVTKRenderWindowInteractor, BasePlotter):
Number of updates per second. Useful for automatically
updating the render window when actors are change without
being automatically ``Modified``.
+
"""
# pylint: disable=too-many-instance-attributes
@@ -185,17 +200,17 @@ class QtInteractor(QVTKRenderWindowInteractor, BasePlotter):
key_press_event_signal = Signal(vtkGenericRenderWindowInteractor, str)
# pylint: disable=too-many-arguments
- def __init__(
+ def __init__( # noqa: C901, PLR0912, PLR0913
self,
parent: MainWindow = None,
- title: str = None,
- off_screen: bool = None,
- multi_samples: int = None,
- line_smoothing: bool = False,
- point_smoothing: bool = False,
- polygon_smoothing: bool = False,
+ title: Optional[str] = None,
+ off_screen: Optional[bool] = None,
+ multi_samples: Optional[int] = None,
+ line_smoothing: bool = False, # noqa: FBT001, FBT002
+ point_smoothing: bool = False, # noqa: FBT001, FBT002
+ polygon_smoothing: bool = False, # noqa: FBT001, FBT002
auto_update: Union[float, bool] = 5.0,
- **kwargs: Any,
+ **kwargs: Any, # noqa: ANN401
) -> None:
# pylint: disable=too-many-branches
"""Initialize Qt interactor."""
@@ -263,34 +278,27 @@ def __init__(
self.render_timer.timeout.connect(self.render)
self.render_timer.start(twait)
- if global_theme.depth_peeling["enabled"]:
- if self.enable_depth_peeling():
- for renderer in self.renderers:
- renderer.enable_depth_peeling()
+ if global_theme.depth_peeling["enabled"] and self.enable_depth_peeling():
+ for renderer in self.renderers:
+ renderer.enable_depth_peeling()
# Set some private attributes that let BasePlotter know
# that this is safely rendering
self._first_time = False # Crucial!
- # self._rendered = True # this is handled in render()
+ # self._rendered = True # this is handled in render() # noqa: ERA001
LOG.debug("QtInteractor init stop")
- def _setup_interactor(self, off_screen: bool) -> None:
+ def _setup_interactor(self, off_screen: bool) -> None: # noqa: FBT001
if off_screen:
self.iren: Any = None
else:
- self.iren = RenderWindowInteractor(
- self, interactor=self.ren_win.GetInteractor()
- )
- self.iren.interactor.RemoveObservers(
- "MouseMoveEvent"
- ) # slows window update?
+ self.iren = RenderWindowInteractor(self, interactor=self.ren_win.GetInteractor())
+ self.iren.interactor.RemoveObservers("MouseMoveEvent") # slows window update?
self.iren.initialize()
self.enable_trackball_style()
def _setup_key_press(self) -> None:
- self._observers: Dict[None, None] = (
- {}
- ) # Map of events to observers of self.iren
+ self._observers: Dict[None, None] = {} # Map of events to observers of self.iren
self.iren.add_observer("KeyPressEvent", self.key_press_event)
self.reset_key_events()
@@ -303,12 +311,12 @@ def gesture_event(self, event: QGestureEvent) -> bool:
self.update()
return True
- def key_press_event(self, obj: Any, event: Any) -> None:
+ def key_press_event(self, obj: Any, event: Any) -> None: # noqa: ANN401
"""Call `key_press_event` using a signal."""
self.key_press_event_signal.emit(obj, event)
@wraps(BasePlotter.render)
- def _render(self, *args: Any, **kwargs: Any) -> BasePlotter.render:
+ def _render(self, *args: Any, **kwargs: Any) -> BasePlotter.render: # noqa: ANN401
"""Wrap ``BasePlotter.render``."""
return BasePlotter.render(self, *args, **kwargs)
@@ -333,10 +341,9 @@ def disable(self) -> None:
self.setDisabled(True)
return BasePlotter.disable(self)
- def link_views_across_plotters(
- self, other_plotter: Any, view: int = 0, other_views: Any = None
- ) -> None:
- """Link the views' cameras across two plotters.
+ def link_views_across_plotters(self, other_plotter: Any, view: int = 0, other_views: Any = None) -> None: # noqa: ANN401
+ """
+ Link the views' cameras across two plotters.
Parameters
----------
@@ -363,18 +370,17 @@ def link_views_across_plotters(
other_views = np.asarray(other_views)
if not np.issubdtype(other_views.dtype, int):
- raise TypeError(
- "Expected `other_views` type is int, or list or tuple of ints, "
- f"but {other_views.dtype} is given"
- )
+ msg = "Expected `other_views` type is int, or list or tuple of ints, " f"but {other_views.dtype} is given"
+ raise TypeError(msg)
renderer = self.renderers[view]
for view_index in other_views:
other_plotter.renderers[view_index].camera = renderer.camera
# pylint: disable=invalid-name
- def dragEnterEvent(self, event: QtGui.QDragEnterEvent) -> None:
- """Event is called when something is dropped onto the vtk window.
+ def dragEnterEvent(self, event: QtGui.QDragEnterEvent) -> None: # noqa: N802
+ """
+ Event is called when something is dropped onto the vtk window.
Only triggers event when event contains file paths that
exist. User can drop anything in this window and we only want
@@ -382,23 +388,23 @@ def dragEnterEvent(self, event: QtGui.QDragEnterEvent) -> None:
"""
try:
for url in event.mimeData().urls():
- if os.path.isfile(url.path()):
+ if os.path.isfile(url.path()): # noqa: PTH113
# only call accept on files
event.accept()
- except IOError as exception: # pragma: no cover
- warnings.warn(f"Exception when dragging files: {str(exception)}")
+ except OSError as exception: # pragma: no cover
+ warnings.warn(f"Exception when dragging files: {exception!s}") # noqa: B028
# pylint: disable=invalid-name,useless-return
- def dropEvent(self, event: QtCore.QEvent) -> None:
+ def dropEvent(self, event: QtCore.QEvent) -> None: # noqa: N802
"""Event is called after dragEnterEvent."""
try:
for url in event.mimeData().urls():
self.url = url
filename = self.url.path()
- if os.path.isfile(filename):
+ if os.path.isfile(filename): # noqa: PTH113
self.add_mesh(pyvista.read(filename))
- except IOError as exception: # pragma: no cover
- warnings.warn(f"Exception when dropping files: {str(exception)}")
+ except OSError as exception: # pragma: no cover
+ warnings.warn(f"Exception when dropping files: {exception!s}") # noqa: B028
def close(self) -> None:
"""Quit application."""
@@ -414,14 +420,13 @@ def close(self) -> None:
_FakeEventHandler()
)
for key in ("_RenderWindow", "renderer"):
- try:
+ with contextlib.suppress(AttributeError):
setattr(self, key, None)
- except AttributeError:
- pass
class BackgroundPlotter(QtInteractor):
- """Qt interactive plotter.
+ """
+ Qt interactive plotter.
Background plotter for pyvista that allows you to maintain an
interactive plotting window without blocking the main python
@@ -493,6 +498,7 @@ class BackgroundPlotter(QtInteractor):
>>> from pyvistaqt import BackgroundPlotter
>>> plotter = BackgroundPlotter()
>>> _ = plotter.add_mesh(pv.Sphere())
+
"""
# pylint: disable=too-many-ancestors
@@ -503,19 +509,19 @@ class BackgroundPlotter(QtInteractor):
# pylint: disable=too-many-arguments
# pylint: disable=too-many-locals
- def __init__(
+ def __init__( # noqa: PLR0913, PLR0915
self,
- show: bool = True,
+ show: bool = True, # noqa: FBT001, FBT002
app: Optional[QApplication] = None,
window_size: Optional[Tuple[int, int]] = None,
off_screen: Optional[bool] = None,
- allow_quit_keypress: bool = True,
- toolbar: bool = True,
- menu_bar: bool = True,
- editor: bool = True,
+ allow_quit_keypress: bool = True, # noqa: FBT001, FBT002
+ toolbar: bool = True, # noqa: FBT001, FBT002
+ menu_bar: bool = True, # noqa: FBT001, FBT002
+ editor: bool = True, # noqa: FBT001, FBT002
update_app_icon: Optional[bool] = None,
app_window_class: Optional[Type[MainWindow]] = None,
- **kwargs: Any,
+ **kwargs: Any, # noqa: ANN401
) -> None:
# pylint: disable=too-many-branches
"""Initialize the qt plotter."""
@@ -563,14 +569,12 @@ def __init__(
self.off_screen = _setup_off_screen(off_screen)
if app_window_class is None:
app_window_class = MainWindow
- self.app_window = app_window_class(
- title=kwargs.get("title", global_theme.title)
- )
+ self.app_window = app_window_class(title=kwargs.get("title", global_theme.title))
self.frame = QFrame(parent=self.app_window)
self.frame.setFrameStyle(QFrame.NoFrame)
vlayout = QVBoxLayout()
super().__init__(parent=self.frame, off_screen=off_screen, **kwargs)
- assert not self._closed
+ assert not self._closed # noqa: S101
vlayout.addWidget(self)
self.frame.setLayout(vlayout)
self.app_window.setCentralWidget(self.frame)
@@ -596,13 +600,9 @@ def __init__(
if update_app_icon:
self.add_callback(self.update_app_icon)
elif update_app_icon is None:
- self.set_icon(
- os.path.join(
- os.path.dirname(__file__), "data", "pyvista_logo_square.png"
- )
- )
+ self.set_icon(os.path.join(os.path.dirname(__file__), "data", "pyvista_logo_square.png")) # noqa: PTH118, PTH120
else:
- assert update_app_icon is False
+ assert update_app_icon is False # noqa: S101
# Keypress events
if self.iren is not None:
@@ -610,7 +610,8 @@ def __init__(
LOG.debug("BackgroundPlotter init stop")
def reset_key_events(self) -> None:
- """Reset all of the key press events to their defaults.
+ """
+ Reset all of the key press events to their defaults.
Handles closing configuration for q-key.
"""
@@ -619,12 +620,13 @@ def reset_key_events(self) -> None:
# pylint: disable=unnecessary-lambda
self.add_key_event("q", lambda: self.close())
- def scale_axes_dialog(self, show: bool = True) -> ScaleAxesDialog:
+ def scale_axes_dialog(self, show: bool = True) -> ScaleAxesDialog: # noqa: FBT001, FBT002
"""Open scale axes dialog."""
return ScaleAxesDialog(self.app_window, self, show=show)
def close(self) -> None:
- """Close the plotter.
+ """
+ Close the plotter.
This function closes the window which in turn will
close the plotter through `signal_close`.
@@ -637,9 +639,9 @@ def close(self) -> None:
# been deleted
#
# So let's be safe and try/except this in case of a problem.
- try:
+ try: # noqa: SIM105
self.app_window.close()
- except Exception: # pragma: no cover # pylint: disable=broad-except
+ except Exception: # pragma: no cover # pylint: disable=broad-except # noqa: S110, BLE001
pass
def _close(self) -> None:
@@ -647,9 +649,7 @@ def _close(self) -> None:
def update_app_icon(self) -> None:
"""Update the app icon if the user is not trying to resize the window."""
- if os.name == "nt" or not hasattr(
- self, "_last_window_size"
- ): # pragma: no cover
+ if os.name == "nt" or not hasattr(self, "_last_window_size"): # pragma: no cover
# DO NOT EVEN ATTEMPT TO UPDATE ICON ON WINDOWS
return
cur_time = time.time()
@@ -657,9 +657,7 @@ def update_app_icon(self) -> None:
# Window size hasn't remained constant since last render.
# This means the user is resizing it so ignore update.
pass
- elif (
- cur_time - self._last_update_time > BackgroundPlotter.ICON_TIME_STEP
- ) and self._last_camera_pos != self.camera_position:
+ elif (cur_time - self._last_update_time > BackgroundPlotter.ICON_TIME_STEP) and self._last_camera_pos != self.camera_position:
# its been a while since last update OR
# the camera position has changed and its been at least one second
@@ -673,7 +671,8 @@ def update_app_icon(self) -> None:
self._last_window_size = self.window_size
def set_icon(self, img: Union[np.ndarray, str]) -> None:
- """Set the icon image.
+ """
+ Set the icon image.
Parameters
----------
@@ -686,41 +685,35 @@ def set_icon(self, img: Union[np.ndarray, str]) -> None:
-----
Currently string paths can silently fail, so make sure your path
is something that produces a valid ``QIcon(img)``.
+
"""
if not (
- isinstance(img, np.ndarray)
- and img.ndim == 3
- and img.shape[0] == img.shape[1]
- and img.dtype == np.uint8
- and img.shape[-1] in (3, 4)
+ isinstance(img, np.ndarray) and img.ndim == 3 and img.shape[0] == img.shape[1] and img.dtype == np.uint8 and img.shape[-1] in (3, 4) # noqa: PLR2004
) and not isinstance(img, str):
- raise ValueError(
- "img must be 3D uint8 ndarray with shape[1] == shape[2] and "
- "shape[2] == 3 or 4, or str"
- )
+ msg = "img must be 3D uint8 ndarray with shape[1] == shape[2] and " "shape[2] == 3 or 4, or str"
+ raise ValueError(msg)
if isinstance(img, np.ndarray):
fmt_str = "Format_RGB"
- fmt_str += ("A8" if img.shape[2] == 4 else "") + "888"
+ fmt_str += ("A8" if img.shape[2] == 4 else "") + "888" # noqa: PLR2004
fmt = getattr(QtGui.QImage, fmt_str)
- img = QtGui.QPixmap.fromImage(
- QtGui.QImage(img.copy(), img.shape[1], img.shape[0], fmt)
- )
+ img = QtGui.QPixmap.fromImage(QtGui.QImage(img.copy(), img.shape[1], img.shape[0], fmt))
# Currently no way to check if str/path is actually correct (want to
# allow resource paths and the like so os.path.isfile is no good)
# and icon.isNull() returns False even if the path is bogus.
self.app.setWindowIcon(QtGui.QIcon(img))
- def _qt_screenshot(self, show: bool = True) -> FileDialog:
+ def _qt_screenshot(self, show: bool = True) -> FileDialog: # noqa: FBT001, FBT002
return FileDialog(
self.app_window,
filefilter=["Image File (*.png)", "JPEG (*.jpeg)"],
show=show,
- directory=bool(os.getcwd()),
+ directory=bool(os.getcwd()), # noqa: PTH109
callback=self.screenshot,
)
- def _qt_export_vtkjs(self, show: bool = True) -> FileDialog:
- """Spawn an save file dialog to export a vtksz file.
+ def _qt_export_vtkjs(self, show: bool = True) -> FileDialog: # noqa: FBT001, FBT002
+ """
+ Spawn an save file dialog to export a vtksz file.
The exported file can be viewed with the OfflineLocalView viewer
available at https://kitware.github.io/vtk-js/examples/OfflineLocalView.html
@@ -728,16 +721,16 @@ def _qt_export_vtkjs(self, show: bool = True) -> FileDialog:
"""
try:
callback = self.export_vtksz
- ext = 'vtksz'
+ ext = "vtksz"
except AttributeError:
callback = self.export_vtkjs # pre-v0.40
- ext = 'vtkjs'
+ ext = "vtkjs"
return FileDialog(
self.app_window,
filefilter=[f"VTK.js File(*.{ext})"],
show=show,
- directory=bool(os.getcwd()),
+ directory=bool(os.getcwd()), # noqa: PTH109
callback=callback,
)
@@ -763,16 +756,15 @@ def window_size(self, window_size: QSize) -> None:
self.app_window.setBaseSize(*window_size)
self.app_window.resize(*window_size)
# NOTE: setting BasePlotter is unnecessary and Segfaults CI
- # BasePlotter.window_size.fset(self, window_size)
+ # BasePlotter.window_size.fset(self, window_size) # noqa: ERA001
def __del__(self) -> None: # pragma: no cover
"""Delete the qt plotter."""
self.close()
- def add_callback(
- self, func: Callable, interval: int = 1000, count: Optional[int] = None
- ) -> None:
- """Add a function that can update the scene in the background.
+ def add_callback(self, func: Callable, interval: int = 1000, count: Optional[int] = None) -> None:
+ """
+ Add a function that can update the scene in the background.
Parameters
----------
@@ -812,7 +804,7 @@ def load_camera_position() -> None:
self.camera_position = camera_position
self.saved_cameras_tool_bar.addAction(f"Cam {ncam}", load_camera_position)
- if ncam < 10:
+ if ncam < 10: # noqa: PLR2004
self.add_key_event(str(ncam), load_camera_position)
def clear_camera_positions(self) -> None:
@@ -823,7 +815,7 @@ def clear_camera_positions(self) -> None:
self.saved_cameras_tool_bar.removeAction(action)
self.saved_camera_positions = []
- def _add_action(self, tool_bar: QToolBar, key: str, method: Any) -> QAction:
+ def _add_action(self, tool_bar: QToolBar, key: str, method: Any) -> QAction: # noqa: ANN401
action = QAction(key, self.app_window)
action.triggered.connect(method)
tool_bar.addAction(action)
@@ -834,7 +826,7 @@ def add_toolbars(self) -> None:
# Camera toolbar
self.default_camera_tool_bar = self.app_window.addToolBar("Camera Position")
- def _view_vector(*args: Any) -> None:
+ def _view_vector(*args: Any) -> None: # noqa: ANN401
return self.view_vector(*args)
cvec_setters = {
@@ -848,23 +840,15 @@ def _view_vector(*args: Any) -> None:
"Isometric": lambda: _view_vector((1, 1, 1), (0, 0, 1)),
}
for key, method in cvec_setters.items():
- self._view_action = self._add_action(
- self.default_camera_tool_bar, key, method
- )
+ self._view_action = self._add_action(self.default_camera_tool_bar, key, method)
# pylint: disable=unnecessary-lambda
- self._add_action(
- self.default_camera_tool_bar, "Reset", lambda: self.reset_camera()
- )
+ self._add_action(self.default_camera_tool_bar, "Reset", lambda: self.reset_camera())
# Saved camera locations toolbar
self.saved_camera_positions = []
- self.saved_cameras_tool_bar = self.app_window.addToolBar(
- "Saved Camera Positions"
- )
+ self.saved_cameras_tool_bar = self.app_window.addToolBar("Saved Camera Positions")
- self._add_action(
- self.saved_cameras_tool_bar, SAVE_CAM_BUTTON_TEXT, self.save_camera_position
- )
+ self._add_action(self.saved_cameras_tool_bar, SAVE_CAM_BUTTON_TEXT, self.save_camera_position)
self._add_action(
self.saved_cameras_tool_bar,
CLEAR_CAMS_BUTTON_TEXT,
@@ -884,9 +868,7 @@ def add_menu_bar(self) -> None:
self._menu_close_action = file_menu.addAction("Exit", self.app_window.close)
view_menu = self.main_menu.addMenu("View")
- self._edl_action = view_menu.addAction(
- "Toggle Eye Dome Lighting", self._toggle_edl
- )
+ self._edl_action = view_menu.addAction("Toggle Eye Dome Lighting", self._toggle_edl)
view_menu.addAction("Scale Axes", self.scale_axes_dialog)
view_menu.addAction("Clear All", self.clear)
@@ -898,9 +880,7 @@ def add_menu_bar(self) -> None:
)
cam_menu = view_menu.addMenu("Camera")
- self._parallel_projection_action = cam_menu.addAction(
- "Toggle Parallel Projection", self._toggle_parallel_projection
- )
+ self._parallel_projection_action = cam_menu.addAction("Toggle Parallel Projection", self._toggle_parallel_projection)
view_menu.addSeparator()
# Orientation marker
@@ -927,7 +907,8 @@ def add_editor(self) -> None:
class MultiPlotter:
- """Qt interactive plotter.
+ """
+ Qt interactive plotter.
Multi plotter for pyvista that allows to maintain an
interactive window with multiple plotters without
@@ -956,21 +937,22 @@ class MultiPlotter:
>>> from pyvistaqt import MultiPlotter
>>> plotter = MultiPlotter()
>>> _ = plotter[0, 0].add_mesh(pv.Sphere())
+
"""
# pylint: disable=too-many-instance-attributes
# pylint: disable=too-many-arguments
- def __init__(
+ def __init__( # noqa: PLR0913
self,
app: Optional[QApplication] = None,
nrows: int = 1,
ncols: int = 1,
- show: bool = True,
+ show: bool = True, # noqa: FBT001, FBT002
window_size: Optional[Tuple[int, int]] = None,
title: Optional[str] = None,
off_screen: Optional[bool] = None,
- **kwargs: Any,
+ **kwargs: Any, # noqa: ANN401
) -> None:
"""Initialize the multi plotter."""
_check_type(app, "app", [QApplication, type(None)])
@@ -1012,8 +994,9 @@ def close(self) -> None:
"""Close the multi plotter."""
self._window.close()
- def __setitem__(self, idx: Tuple[int, int], plotter: Any) -> None:
- """Set a valid plotter in the grid.
+ def __setitem__(self, idx: Tuple[int, int], plotter: Any) -> None: # noqa: ANN401
+ """
+ Set a valid plotter in the grid.
Parameters
----------
@@ -1022,12 +1005,14 @@ def __setitem__(self, idx: Tuple[int, int], plotter: Any) -> None:
be an integer or a tuple ``(row, col)``.
plotter : BackgroundPlotter
The plotter to set.
+
"""
row, col = idx
self._plotters[row * self._ncols + col] = plotter
def __getitem__(self, idx: Tuple[int, int]) -> Optional[BackgroundPlotter]:
- """Get a valid plotter in the grid.
+ """
+ Get a valid plotter in the grid.
Parameters
----------
@@ -1039,6 +1024,7 @@ def __getitem__(self, idx: Tuple[int, int]) -> Optional[BackgroundPlotter]:
-------
plotter : BackgroundPlotter
The selected plotter.
+
"""
row, col = idx
self._plotter = self._plotters[row * self._ncols + col]
diff --git a/pyvistaqt/rwi.py b/pyvistaqt/rwi.py
index 9730b8ab..7ed1ca70 100644
--- a/pyvistaqt/rwi.py
+++ b/pyvistaqt/rwi.py
@@ -1,6 +1,6 @@
# modified from: https://gitlab.kitware.com/vtk/vtk
# under the OSI-approved BSD 3-clause License
-# TODO: Mayavi has a potentially different version that might be better or worse
+# TODO: Mayavi has a potentially different version that might be better or worse # noqa: FIX002, TD002, TD003
# coding=utf-8
"""
A simple VTK widget for PyQt or PySide.
@@ -54,11 +54,14 @@
Changes by Eric Larson and Guillaume Favelier, Apr. 2022
Support for PyQt6
-"""
+""" # noqa: D205
# Check whether a specific PyQt implementation was chosen
+from __future__ import annotations
+
try:
import vtkmodules.qt
+
PyQtImpl = vtkmodules.qt.PyQtImpl
except ImportError:
pass
@@ -70,46 +73,57 @@
QVTKRWIBase = "QWidget"
try:
import vtkmodules.qt
+
QVTKRWIBase = vtkmodules.qt.QVTKRWIBase
except ImportError:
pass
-from vtkmodules.vtkRenderingCore import vtkRenderWindow
-from vtkmodules.vtkRenderingUI import vtkGenericRenderWindowInteractor
+from vtkmodules.vtkRenderingCore import vtkRenderWindow # noqa: E402
+from vtkmodules.vtkRenderingUI import vtkGenericRenderWindowInteractor # noqa: E402
if PyQtImpl is None:
# Autodetect the PyQt implementation to use
try:
- import PyQt6
+ import PyQt6 # noqa: F401
+
PyQtImpl = "PyQt6"
except ImportError:
try:
- import PySide6
+ import PySide6 # noqa: F401
+
PyQtImpl = "PySide6"
except ImportError:
try:
- import PyQt5
+ import PyQt5 # noqa: F401
+
PyQtImpl = "PyQt5"
except ImportError:
try:
- import PySide2
+ import PySide2 # noqa: F401
+
PyQtImpl = "PySide2"
except ImportError:
try:
- import PyQt4
+ import PyQt4 # noqa: F401
+
PyQtImpl = "PyQt4"
except ImportError:
try:
- import PySide
+ import PySide # noqa: F401
+
PyQtImpl = "PySide"
except ImportError:
- raise ImportError("Cannot load either PyQt or PySide")
+ msg = "Cannot load either PyQt or PySide"
+ raise ImportError(msg) # noqa: B904
# Check the compatibility of PyQtImpl and QVTKRWIBase
if QVTKRWIBase != "QWidget":
- if PyQtImpl in ["PyQt6", "PySide6"] and QVTKRWIBase == "QOpenGLWidget":
- pass # compatible
- elif PyQtImpl in ["PyQt5", "PySide2","PyQt4", "PySide"] and QVTKRWIBase == "QGLWidget":
+ if (
+ PyQtImpl in ["PyQt6", "PySide6"]
+ and QVTKRWIBase == "QOpenGLWidget"
+ or PyQtImpl in ["PyQt5", "PySide2", "PyQt4", "PySide"]
+ and QVTKRWIBase == "QGLWidget"
+ ):
pass # compatible
else:
raise ImportError("Cannot load " + QVTKRWIBase + " from " + PyQtImpl)
@@ -117,79 +131,73 @@
if PyQtImpl == "PyQt6":
if QVTKRWIBase == "QOpenGLWidget":
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
- from PyQt6.QtWidgets import QWidget
- from PyQt6.QtWidgets import QSizePolicy
- from PyQt6.QtWidgets import QApplication
- from PyQt6.QtWidgets import QMainWindow
- from PyQt6.QtGui import QCursor
+ from PyQt6.QtCore import QEvent
+ from PyQt6.QtCore import QSize
from PyQt6.QtCore import Qt
from PyQt6.QtCore import QTimer
- from PyQt6.QtCore import QObject
- from PyQt6.QtCore import QSize
- from PyQt6.QtCore import QEvent
+ from PyQt6.QtGui import QCursor
+ from PyQt6.QtWidgets import QApplication
+ from PyQt6.QtWidgets import QMainWindow
+ from PyQt6.QtWidgets import QSizePolicy
+ from PyQt6.QtWidgets import QWidget
elif PyQtImpl == "PySide6":
if QVTKRWIBase == "QOpenGLWidget":
from PySide6.QtOpenGLWidgets import QOpenGLWidget
- from PySide6.QtWidgets import QWidget
- from PySide6.QtWidgets import QSizePolicy
- from PySide6.QtWidgets import QApplication
- from PySide6.QtWidgets import QMainWindow
- from PySide6.QtGui import QCursor
+ from PySide6.QtCore import QEvent
+ from PySide6.QtCore import QSize
from PySide6.QtCore import Qt
from PySide6.QtCore import QTimer
- from PySide6.QtCore import QObject
- from PySide6.QtCore import QSize
- from PySide6.QtCore import QEvent
+ from PySide6.QtGui import QCursor
+ from PySide6.QtWidgets import QApplication
+ from PySide6.QtWidgets import QMainWindow
+ from PySide6.QtWidgets import QSizePolicy
+ from PySide6.QtWidgets import QWidget
elif PyQtImpl == "PyQt5":
if QVTKRWIBase == "QGLWidget":
from PyQt5.QtOpenGL import QGLWidget
- from PyQt5.QtWidgets import QWidget
- from PyQt5.QtWidgets import QSizePolicy
- from PyQt5.QtWidgets import QApplication
- from PyQt5.QtWidgets import QMainWindow
- from PyQt5.QtGui import QCursor
+ from PyQt5.QtCore import QEvent
+ from PyQt5.QtCore import QSize
from PyQt5.QtCore import Qt
from PyQt5.QtCore import QTimer
- from PyQt5.QtCore import QObject
- from PyQt5.QtCore import QSize
- from PyQt5.QtCore import QEvent
+ from PyQt5.QtGui import QCursor
+ from PyQt5.QtWidgets import QApplication
+ from PyQt5.QtWidgets import QMainWindow
+ from PyQt5.QtWidgets import QSizePolicy
+ from PyQt5.QtWidgets import QWidget
elif PyQtImpl == "PySide2":
if QVTKRWIBase == "QGLWidget":
from PySide2.QtOpenGL import QGLWidget
- from PySide2.QtWidgets import QWidget
- from PySide2.QtWidgets import QSizePolicy
- from PySide2.QtWidgets import QApplication
- from PySide2.QtWidgets import QMainWindow
- from PySide2.QtGui import QCursor
+ from PySide2.QtCore import QEvent
+ from PySide2.QtCore import QSize
from PySide2.QtCore import Qt
from PySide2.QtCore import QTimer
- from PySide2.QtCore import QObject
- from PySide2.QtCore import QSize
- from PySide2.QtCore import QEvent
+ from PySide2.QtGui import QCursor
+ from PySide2.QtWidgets import QApplication
+ from PySide2.QtWidgets import QMainWindow
+ from PySide2.QtWidgets import QSizePolicy
+ from PySide2.QtWidgets import QWidget
elif PyQtImpl == "PyQt4":
if QVTKRWIBase == "QGLWidget":
from PyQt4.QtOpenGL import QGLWidget
- from PyQt4.QtGui import QWidget
- from PyQt4.QtGui import QSizePolicy
- from PyQt4.QtGui import QApplication
- from PyQt4.QtGui import QMainWindow
+ from PyQt4.QtCore import QEvent
+ from PyQt4.QtCore import QSize
from PyQt4.QtCore import Qt
from PyQt4.QtCore import QTimer
- from PyQt4.QtCore import QObject
- from PyQt4.QtCore import QSize
- from PyQt4.QtCore import QEvent
+ from PyQt4.QtGui import QApplication
+ from PyQt4.QtGui import QMainWindow
+ from PyQt4.QtGui import QSizePolicy
+ from PyQt4.QtGui import QWidget
elif PyQtImpl == "PySide":
if QVTKRWIBase == "QGLWidget":
from PySide.QtOpenGL import QGLWidget
- from PySide.QtGui import QWidget
- from PySide.QtGui import QSizePolicy
- from PySide.QtGui import QApplication
- from PySide.QtGui import QMainWindow
+ from PySide.QtCore import QEvent
+ from PySide.QtCore import QSize
from PySide.QtCore import Qt
from PySide.QtCore import QTimer
- from PySide.QtCore import QObject
- from PySide.QtCore import QSize
- from PySide.QtCore import QEvent
+ from PySide.QtGui import QApplication
+ from PySide.QtGui import QMainWindow
+ from PySide.QtGui import QSizePolicy
+ from PySide.QtGui import QWidget
else:
raise ImportError("Unknown PyQt implementation " + repr(PyQtImpl))
@@ -203,7 +211,7 @@
else:
raise ImportError("Unknown base class for QVTKRenderWindowInteractor " + QVTKRWIBase)
-if PyQtImpl == 'PyQt6':
+if PyQtImpl == "PyQt6":
CursorShape = Qt.CursorShape
MouseButton = Qt.MouseButton
WindowType = Qt.WindowType
@@ -215,18 +223,14 @@
SizePolicy = QSizePolicy.Policy
EventType = QEvent.Type
else:
- CursorShape = MouseButton = WindowType = WidgetAttribute = \
- KeyboardModifier = FocusPolicy = ConnectionType = Key = Qt
+ CursorShape = MouseButton = WindowType = WidgetAttribute = KeyboardModifier = FocusPolicy = ConnectionType = Key = Qt
SizePolicy = QSizePolicy
EventType = QEvent
-if PyQtImpl in ('PyQt4', 'PySide'):
- MiddleButton = MouseButton.MidButton
-else:
- MiddleButton = MouseButton.MiddleButton
+MiddleButton = MouseButton.MidButton if PyQtImpl in ("PyQt4", "PySide") else MouseButton.MiddleButton
-def _get_event_pos(ev):
+def _get_event_pos(ev): # noqa: ANN001, ANN202
try: # Qt6+
return ev.position().x(), ev.position().y()
except AttributeError: # Qt5
@@ -234,8 +238,8 @@ def _get_event_pos(ev):
class QVTKRenderWindowInteractor(QVTKRWIBaseClass):
-
- """ A QVTKRenderWindowInteractor for Python and Qt. Uses a
+ """
+ A QVTKRenderWindowInteractor for Python and Qt. Uses a
vtkGenericRenderWindowInteractor to handle the interactions. Use
GetRenderWindow() to get the vtkRenderWindow. Create with the
keyword stereo=1 in order to generate a stereo-capable window.
@@ -300,24 +304,24 @@ class QVTKRenderWindowInteractor(QVTKRWIBaseClass):
- Keypress w: modify the representation of all actors so that they
are wireframe.
- """
+ """ # noqa: D205
# Map between VTK and Qt cursors.
- _CURSOR_MAP = {
- 0: CursorShape.ArrowCursor, # VTK_CURSOR_DEFAULT
- 1: CursorShape.ArrowCursor, # VTK_CURSOR_ARROW
- 2: CursorShape.SizeBDiagCursor, # VTK_CURSOR_SIZENE
- 3: CursorShape.SizeFDiagCursor, # VTK_CURSOR_SIZENWSE
- 4: CursorShape.SizeBDiagCursor, # VTK_CURSOR_SIZESW
- 5: CursorShape.SizeFDiagCursor, # VTK_CURSOR_SIZESE
- 6: CursorShape.SizeVerCursor, # VTK_CURSOR_SIZENS
- 7: CursorShape.SizeHorCursor, # VTK_CURSOR_SIZEWE
- 8: CursorShape.SizeAllCursor, # VTK_CURSOR_SIZEALL
- 9: CursorShape.PointingHandCursor, # VTK_CURSOR_HAND
- 10: CursorShape.CrossCursor, # VTK_CURSOR_CROSSHAIR
+ _CURSOR_MAP = { # noqa: RUF012
+ 0: CursorShape.ArrowCursor, # VTK_CURSOR_DEFAULT
+ 1: CursorShape.ArrowCursor, # VTK_CURSOR_ARROW
+ 2: CursorShape.SizeBDiagCursor, # VTK_CURSOR_SIZENE
+ 3: CursorShape.SizeFDiagCursor, # VTK_CURSOR_SIZENWSE
+ 4: CursorShape.SizeBDiagCursor, # VTK_CURSOR_SIZESW
+ 5: CursorShape.SizeFDiagCursor, # VTK_CURSOR_SIZESE
+ 6: CursorShape.SizeVerCursor, # VTK_CURSOR_SIZENS
+ 7: CursorShape.SizeHorCursor, # VTK_CURSOR_SIZEWE
+ 8: CursorShape.SizeAllCursor, # VTK_CURSOR_SIZEALL
+ 9: CursorShape.PointingHandCursor, # VTK_CURSOR_HAND
+ 10: CursorShape.CrossCursor, # VTK_CURSOR_CROSSHAIR
}
- def __init__(self, parent=None, **kw):
+ def __init__(self, parent=None, **kw) -> None: # noqa: ANN001, ANN003, C901, D107, PLR0915
# the current button
self._ActiveButton = MouseButton.NoButton
@@ -332,65 +336,67 @@ def __init__(self, parent=None, **kw):
# stereo, rw
try:
- stereo = bool(kw['stereo'])
+ stereo = bool(kw["stereo"])
except KeyError:
stereo = False
try:
- rw = kw['rw']
+ rw = kw["rw"]
except KeyError:
rw = None
# create base qt-level widget
if QVTKRWIBase == "QWidget":
- if "wflags" in kw:
- wflags = kw['wflags']
- else:
- wflags = Qt.WindowType.Widget
+ wflags = kw.get("wflags", Qt.WindowType.Widget)
QWidget.__init__(self, parent, wflags | WindowType.MSWindowsOwnDC)
elif QVTKRWIBase == "QGLWidget":
QGLWidget.__init__(self, parent)
elif QVTKRWIBase == "QOpenGLWidget":
QOpenGLWidget.__init__(self, parent)
- if rw: # user-supplied render window
+ if rw: # user-supplied render window
self._RenderWindow = rw
else:
self._RenderWindow = vtkRenderWindow()
- WId = self.winId()
+ WId = self.winId() # noqa: N806
# Python2
- if type(WId).__name__ == 'PyCObject':
- from ctypes import pythonapi, c_void_p, py_object
+ if type(WId).__name__ == "PyCObject":
+ from ctypes import c_void_p
+ from ctypes import py_object
+ from ctypes import pythonapi
- pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
+ pythonapi.PyCObject_AsVoidPtr.restype = c_void_p
pythonapi.PyCObject_AsVoidPtr.argtypes = [py_object]
- WId = pythonapi.PyCObject_AsVoidPtr(WId)
+ WId = pythonapi.PyCObject_AsVoidPtr(WId) # noqa: N806
# Python3
- elif type(WId).__name__ == 'PyCapsule':
- from ctypes import pythonapi, c_void_p, py_object, c_char_p
+ elif type(WId).__name__ == "PyCapsule":
+ from ctypes import c_char_p
+ from ctypes import c_void_p
+ from ctypes import py_object
+ from ctypes import pythonapi
pythonapi.PyCapsule_GetName.restype = c_char_p
pythonapi.PyCapsule_GetName.argtypes = [py_object]
name = pythonapi.PyCapsule_GetName(WId)
- pythonapi.PyCapsule_GetPointer.restype = c_void_p
+ pythonapi.PyCapsule_GetPointer.restype = c_void_p
pythonapi.PyCapsule_GetPointer.argtypes = [py_object, c_char_p]
- WId = pythonapi.PyCapsule_GetPointer(WId, name)
+ WId = pythonapi.PyCapsule_GetPointer(WId, name) # noqa: N806
self._RenderWindow.SetWindowInfo(str(int(WId)))
- if stereo: # stereo mode
+ if stereo: # stereo mode
self._RenderWindow.StereoCapableWindowOn()
self._RenderWindow.SetStereoTypeToCrystalEyes()
try:
- self._Iren = kw['iren']
+ self._Iren = kw["iren"]
except KeyError:
self._Iren = vtkGenericRenderWindowInteractor()
self._Iren.SetRenderWindow(self._RenderWindow)
@@ -398,17 +404,16 @@ def __init__(self, parent=None, **kw):
# do all the necessary qt setup
self.setAttribute(WidgetAttribute.WA_OpaquePaintEvent)
self.setAttribute(WidgetAttribute.WA_PaintOnScreen)
- self.setMouseTracking(True) # get all mouse events
+ self.setMouseTracking(True) # get all mouse events
self.setFocusPolicy(FocusPolicy.WheelFocus)
self.setSizePolicy(QSizePolicy(SizePolicy.Expanding, SizePolicy.Expanding))
self._Timer = QTimer(self)
self._Timer.timeout.connect(self.TimerEvent)
- self._Iren.AddObserver('CreateTimerEvent', self.CreateTimer)
- self._Iren.AddObserver('DestroyTimerEvent', self.DestroyTimer)
- self._Iren.GetRenderWindow().AddObserver('CursorChangedEvent',
- self.CursorChangedEvent)
+ self._Iren.AddObserver("CreateTimerEvent", self.CreateTimer)
+ self._Iren.AddObserver("DestroyTimerEvent", self.DestroyTimer)
+ self._Iren.GetRenderWindow().AddObserver("CursorChangedEvent", self.CursorChangedEvent)
# If we've a parent, it does not close the child when closed.
# Connect the parent's destroyed signal to this widget's close
@@ -416,104 +421,101 @@ def __init__(self, parent=None, **kw):
if self.parent():
self.parent().destroyed.connect(self.close, ConnectionType.DirectConnection)
- def __getattr__(self, attr):
- """Makes the object behave like a vtkGenericRenderWindowInteractor"""
- if attr == '__vtk__':
+ def __getattr__(self, attr): # noqa: ANN001, ANN204
+ """Makes the object behave like a vtkGenericRenderWindowInteractor.""" # noqa: D401
+ if attr == "__vtk__":
return lambda t=self._Iren: t
- elif hasattr(self._Iren, attr):
+ if hasattr(self._Iren, attr):
return getattr(self._Iren, attr)
- else:
- raise AttributeError(self.__class__.__name__ +
- " has no attribute named " + attr)
+ raise AttributeError(self.__class__.__name__ + " has no attribute named " + attr)
- def Finalize(self):
- '''
- Call internal cleanup method on VTK objects
- '''
+ def Finalize(self) -> None: # noqa: N802
+ """Call internal cleanup method on VTK objects."""
self._RenderWindow.Finalize()
- def CreateTimer(self, obj, evt):
+ def CreateTimer(self, obj, evt) -> None: # noqa: ANN001, ARG002, N802, D102
self._Timer.start(10)
- def DestroyTimer(self, obj, evt):
+ def DestroyTimer(self, obj, evt) -> int: # noqa: ANN001, ARG002, N802, D102
self._Timer.stop()
return 1
- def TimerEvent(self):
+ def TimerEvent(self) -> None: # noqa: N802, D102
self._Iren.TimerEvent()
- def CursorChangedEvent(self, obj, evt):
- """Called when the CursorChangedEvent fires on the render window."""
+ def CursorChangedEvent(self, obj, evt) -> None: # noqa: ANN001, ARG002, N802
+ """Called when the CursorChangedEvent fires on the render window.""" # noqa: D401
# This indirection is needed since when the event fires, the current
# cursor is not yet set so we defer this by which time the current
# cursor should have been set.
QTimer.singleShot(0, self.ShowCursor)
- def HideCursor(self):
+ def HideCursor(self) -> None: # noqa: N802
"""Hides the cursor."""
self.setCursor(Qt.BlankCursor)
- def ShowCursor(self):
- """Shows the cursor."""
+ def ShowCursor(self) -> None: # noqa: N802
+ """Shows the cursor.""" # noqa: D401
vtk_cursor = self._Iren.GetRenderWindow().GetCurrentCursor()
qt_cursor = self._CURSOR_MAP.get(vtk_cursor, Qt.ArrowCursor)
self.setCursor(qt_cursor)
- def closeEvent(self, evt):
+ def closeEvent(self, evt) -> None: # noqa: ANN001, ARG002, N802, D102
self.Finalize()
- def sizeHint(self):
+ def sizeHint(self): # noqa: ANN201, N802, D102
return QSize(400, 400)
- def paintEngine(self):
+ def paintEngine(self) -> None: # noqa: N802, D102
return None
- def paintEvent(self, ev):
+ def paintEvent(self, ev) -> None: # noqa: ANN001, ARG002, N802, D102
self._Iren.Render()
- def resizeEvent(self, ev):
+ def resizeEvent(self, ev) -> None: # noqa: ANN001, ARG002, N802, D102
scale = self._getPixelRatio()
- w = int(round(scale*self.width()))
- h = int(round(scale*self.height()))
+ w = int(round(scale * self.width()))
+ h = int(round(scale * self.height()))
if self._RenderWindow is None:
return
- self._RenderWindow.SetDPI(int(round(72*scale)))
+ self._RenderWindow.SetDPI(int(round(72 * scale)))
vtkRenderWindow.SetSize(self._RenderWindow, w, h)
self._Iren.SetSize(w, h)
self._Iren.ConfigureEvent()
self.update()
- def _GetKeyCharAndKeySym(self, ev):
- """ Convert a Qt key into a char and a vtk keysym.
+ def _GetKeyCharAndKeySym(self, ev): # noqa: ANN001, ANN202, N802
+ """
+ Convert a Qt key into a char and a vtk keysym.
This is essentially copied from the c++ implementation in
GUISupport/Qt/QVTKInteractorAdapter.cxx.
"""
# if there is a char, convert its ASCII code to a VTK keysym
try:
- keyChar = ev.text()[0]
- keySym = _keysyms_for_ascii[ord(keyChar)]
+ keyChar = ev.text()[0] # noqa: N806
+ keySym = _keysyms_for_ascii[ord(keyChar)] # noqa: N806
except IndexError:
- keyChar = '\0'
- keySym = None
+ keyChar = "\0" # noqa: N806
+ keySym = None # noqa: N806
# next, try converting Qt key code to a VTK keysym
if keySym is None:
try:
- keySym = _keysyms[ev.key()]
+ keySym = _keysyms[ev.key()] # noqa: N806
except KeyError:
- keySym = None
+ keySym = None # noqa: N806
# use "None" as a fallback
if keySym is None:
- keySym = "None"
+ keySym = "None" # noqa: N806
return keyChar, keySym
- def _GetCtrlShift(self, ev):
+ def _GetCtrlShift(self, ev): # noqa: ANN001, ANN202, N802
ctrl = shift = False
- if hasattr(ev, 'modifiers'):
+ if hasattr(ev, "modifiers"):
if ev.modifiers() & KeyboardModifier.ShiftModifier:
shift = True
if ev.modifiers() & KeyboardModifier.ControlModifier:
@@ -527,48 +529,41 @@ def _GetCtrlShift(self, ev):
return ctrl, shift
@staticmethod
- def _getPixelRatio():
+ def _getPixelRatio(): # noqa: ANN205, N802
if PyQtImpl in ("PyQt4", "PySide"):
# Qt4 seems not to provide any cross-platform means to get the
# pixel ratio.
- return 1.
- else:
- # Source: https://stackoverflow.com/a/40053864/3388962
- pos = QCursor.pos()
- for screen in QApplication.screens():
- rect = screen.geometry()
- if rect.contains(pos):
- return screen.devicePixelRatio()
- # Should never happen, but try to find a good fallback.
- return QApplication.instance().devicePixelRatio()
-
- def _setEventInformation(self, x, y, ctrl, shift,
- key, repeat=0, keysum=None):
+ return 1.0
+ # Source: https://stackoverflow.com/a/40053864/3388962
+ pos = QCursor.pos()
+ for screen in QApplication.screens():
+ rect = screen.geometry()
+ if rect.contains(pos):
+ return screen.devicePixelRatio()
+ # Should never happen, but try to find a good fallback.
+ return QApplication.instance().devicePixelRatio()
+
+ def _setEventInformation(self, x, y, ctrl, shift, key, repeat=0, keysum=None) -> None: # noqa: ANN001, N802, PLR0913
scale = self._getPixelRatio()
- self._Iren.SetEventInformation(int(round(x*scale)),
- int(round((self.height()-y-1)*scale)),
- ctrl, shift, key, repeat, keysum)
+ self._Iren.SetEventInformation(int(round(x * scale)), int(round((self.height() - y - 1) * scale)), ctrl, shift, key, repeat, keysum)
- def enterEvent(self, ev):
+ def enterEvent(self, ev) -> None: # noqa: ANN001, N802, D102
ctrl, shift = self._GetCtrlShift(ev)
- self._setEventInformation(self.__saveX, self.__saveY,
- ctrl, shift, chr(0), 0, None)
+ self._setEventInformation(self.__saveX, self.__saveY, ctrl, shift, chr(0), 0, None)
self._Iren.EnterEvent()
- def leaveEvent(self, ev):
+ def leaveEvent(self, ev) -> None: # noqa: ANN001, N802, D102
ctrl, shift = self._GetCtrlShift(ev)
- self._setEventInformation(self.__saveX, self.__saveY,
- ctrl, shift, chr(0), 0, None)
+ self._setEventInformation(self.__saveX, self.__saveY, ctrl, shift, chr(0), 0, None)
self._Iren.LeaveEvent()
- def mousePressEvent(self, ev):
+ def mousePressEvent(self, ev) -> None: # noqa: ANN001, N802, D102
pos_x, pos_y = _get_event_pos(ev)
ctrl, shift = self._GetCtrlShift(ev)
repeat = 0
if ev.type() == EventType.MouseButtonDblClick:
repeat = 1
- self._setEventInformation(pos_x, pos_y,
- ctrl, shift, chr(0), repeat, None)
+ self._setEventInformation(pos_x, pos_y, ctrl, shift, chr(0), repeat, None)
self._ActiveButton = ev.button()
@@ -579,11 +574,10 @@ def mousePressEvent(self, ev):
elif self._ActiveButton == MiddleButton:
self._Iren.MiddleButtonPressEvent()
- def mouseReleaseEvent(self, ev):
+ def mouseReleaseEvent(self, ev) -> None: # noqa: ANN001, N802, D102
pos_x, pos_y = _get_event_pos(ev)
ctrl, shift = self._GetCtrlShift(ev)
- self._setEventInformation(pos_x, pos_y,
- ctrl, shift, chr(0), 0, None)
+ self._setEventInformation(pos_x, pos_y, ctrl, shift, chr(0), 0, None)
if self._ActiveButton == MouseButton.LeftButton:
self._Iren.LeftButtonReleaseEvent()
@@ -592,7 +586,7 @@ def mouseReleaseEvent(self, ev):
elif self._ActiveButton == MiddleButton:
self._Iren.MiddleButtonReleaseEvent()
- def mouseMoveEvent(self, ev):
+ def mouseMoveEvent(self, ev) -> None: # noqa: ANN001, N802, D102
pos_x, pos_y = _get_event_pos(ev)
self.__saveModifiers = ev.modifiers()
self.__saveButtons = ev.buttons()
@@ -600,53 +594,50 @@ def mouseMoveEvent(self, ev):
self.__saveY = pos_y
ctrl, shift = self._GetCtrlShift(ev)
- self._setEventInformation(pos_x, pos_y,
- ctrl, shift, chr(0), 0, None)
+ self._setEventInformation(pos_x, pos_y, ctrl, shift, chr(0), 0, None)
self._Iren.MouseMoveEvent()
- def keyPressEvent(self, ev):
- key, keySym = self._GetKeyCharAndKeySym(ev)
+ def keyPressEvent(self, ev) -> None: # noqa: ANN001, N802, D102
+ key, keySym = self._GetKeyCharAndKeySym(ev) # noqa: N806
ctrl, shift = self._GetCtrlShift(ev)
- self._setEventInformation(self.__saveX, self.__saveY,
- ctrl, shift, key, 0, keySym)
+ self._setEventInformation(self.__saveX, self.__saveY, ctrl, shift, key, 0, keySym)
self._Iren.KeyPressEvent()
self._Iren.CharEvent()
- def keyReleaseEvent(self, ev):
- key, keySym = self._GetKeyCharAndKeySym(ev)
+ def keyReleaseEvent(self, ev) -> None: # noqa: ANN001, N802, D102
+ key, keySym = self._GetKeyCharAndKeySym(ev) # noqa: N806
ctrl, shift = self._GetCtrlShift(ev)
- self._setEventInformation(self.__saveX, self.__saveY,
- ctrl, shift, key, 0, keySym)
+ self._setEventInformation(self.__saveX, self.__saveY, ctrl, shift, key, 0, keySym)
self._Iren.KeyReleaseEvent()
- def wheelEvent(self, ev):
- if hasattr(ev, 'delta'):
+ def wheelEvent(self, ev) -> None: # noqa: ANN001, N802, D102
+ if hasattr(ev, "delta"):
self.__wheelDelta += ev.delta()
else:
self.__wheelDelta += ev.angleDelta().y()
- if self.__wheelDelta >= 120:
+ if self.__wheelDelta >= 120: # noqa: PLR2004
self._Iren.MouseWheelForwardEvent()
self.__wheelDelta = 0
- elif self.__wheelDelta <= -120:
+ elif self.__wheelDelta <= -120: # noqa: PLR2004
self._Iren.MouseWheelBackwardEvent()
self.__wheelDelta = 0
- def GetRenderWindow(self):
+ def GetRenderWindow(self): # noqa: ANN201, N802, D102
return self._RenderWindow
- def Render(self):
+ def Render(self) -> None: # noqa: N802, D102
self.update()
-def QVTKRenderWidgetConeExample(block=False):
- """A simple example that uses the QVTKRenderWindowInteractor class."""
-
+def QVTKRenderWidgetConeExample(block=False) -> None: # noqa: ANN001, FBT002, N802
+ """A simple example that uses the QVTKRenderWindowInteractor class.""" # noqa: D401
from vtkmodules.vtkFiltersSources import vtkConeSource
- from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkRenderer
+ from vtkmodules.vtkRenderingCore import vtkActor
+ from vtkmodules.vtkRenderingCore import vtkPolyDataMapper
+ from vtkmodules.vtkRenderingCore import vtkRenderer
+
# load implementations for rendering and interaction factory classes
- import vtkmodules.vtkRenderingOpenGL2
- import vtkmodules.vtkInteractionStyle
# every QT app needs an app
app = QApplication.instance()
@@ -659,7 +650,7 @@ def QVTKRenderWidgetConeExample(block=False):
widget = QVTKRenderWindowInteractor(window)
window.setCentralWidget(widget)
# if you don't want the 'q' key to exit comment this.
- widget.AddObserver("ExitEvent", lambda o, e, a=app: a.quit())
+ widget.AddObserver("ExitEvent", lambda o, e, a=app: a.quit()) # noqa: ARG005
ren = vtkRenderer()
widget.GetRenderWindow().AddRenderer(ren)
@@ -667,10 +658,10 @@ def QVTKRenderWidgetConeExample(block=False):
cone = vtkConeSource()
cone.SetResolution(8)
- coneMapper = vtkPolyDataMapper()
+ coneMapper = vtkPolyDataMapper() # noqa: N806
coneMapper.SetInputConnection(cone.GetOutputPort())
- coneActor = vtkActor()
+ coneActor = vtkActor() # noqa: N806
coneActor.SetMapper(coneMapper)
ren.AddActor(coneActor)
@@ -693,123 +684,231 @@ def QVTKRenderWidgetConeExample(block=False):
_keysyms_for_ascii = (
- None, None, None, None, None, None, None, None,
- None, "Tab", None, None, None, None, None, None,
- None, None, None, None, None, None, None, None,
- None, None, None, None, None, None, None, None,
- "space", "exclam", "quotedbl", "numbersign",
- "dollar", "percent", "ampersand", "quoteright",
- "parenleft", "parenright", "asterisk", "plus",
- "comma", "minus", "period", "slash",
- "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "colon", "semicolon", "less", "equal", "greater", "question",
- "at", "A", "B", "C", "D", "E", "F", "G",
- "H", "I", "J", "K", "L", "M", "N", "O",
- "P", "Q", "R", "S", "T", "U", "V", "W",
- "X", "Y", "Z", "bracketleft",
- "backslash", "bracketright", "asciicircum", "underscore",
- "quoteleft", "a", "b", "c", "d", "e", "f", "g",
- "h", "i", "j", "k", "l", "m", "n", "o",
- "p", "q", "r", "s", "t", "u", "v", "w",
- "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Delete",
- )
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ "Tab",
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "minus",
+ "period",
+ "slash",
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "Delete",
+)
_keysyms = {
- Key.Key_Backspace: 'BackSpace',
- Key.Key_Tab: 'Tab',
- Key.Key_Backtab: 'Tab',
+ Key.Key_Backspace: "BackSpace",
+ Key.Key_Tab: "Tab",
+ Key.Key_Backtab: "Tab",
# Key.Key_Clear : 'Clear',
- Key.Key_Return: 'Return',
- Key.Key_Enter: 'Return',
- Key.Key_Shift: 'Shift_L',
- Key.Key_Control: 'Control_L',
- Key.Key_Alt: 'Alt_L',
- Key.Key_Pause: 'Pause',
- Key.Key_CapsLock: 'Caps_Lock',
- Key.Key_Escape: 'Escape',
- Key.Key_Space: 'space',
+ Key.Key_Return: "Return",
+ Key.Key_Enter: "Return",
+ Key.Key_Shift: "Shift_L",
+ Key.Key_Control: "Control_L",
+ Key.Key_Alt: "Alt_L",
+ Key.Key_Pause: "Pause",
+ Key.Key_CapsLock: "Caps_Lock",
+ Key.Key_Escape: "Escape",
+ Key.Key_Space: "space",
# Key.Key_Prior : 'Prior',
# Key.Key_Next : 'Next',
- Key.Key_End: 'End',
- Key.Key_Home: 'Home',
- Key.Key_Left: 'Left',
- Key.Key_Up: 'Up',
- Key.Key_Right: 'Right',
- Key.Key_Down: 'Down',
- Key.Key_SysReq: 'Snapshot',
- Key.Key_Insert: 'Insert',
- Key.Key_Delete: 'Delete',
- Key.Key_Help: 'Help',
- Key.Key_0: '0',
- Key.Key_1: '1',
- Key.Key_2: '2',
- Key.Key_3: '3',
- Key.Key_4: '4',
- Key.Key_5: '5',
- Key.Key_6: '6',
- Key.Key_7: '7',
- Key.Key_8: '8',
- Key.Key_9: '9',
- Key.Key_A: 'a',
- Key.Key_B: 'b',
- Key.Key_C: 'c',
- Key.Key_D: 'd',
- Key.Key_E: 'e',
- Key.Key_F: 'f',
- Key.Key_G: 'g',
- Key.Key_H: 'h',
- Key.Key_I: 'i',
- Key.Key_J: 'j',
- Key.Key_K: 'k',
- Key.Key_L: 'l',
- Key.Key_M: 'm',
- Key.Key_N: 'n',
- Key.Key_O: 'o',
- Key.Key_P: 'p',
- Key.Key_Q: 'q',
- Key.Key_R: 'r',
- Key.Key_S: 's',
- Key.Key_T: 't',
- Key.Key_U: 'u',
- Key.Key_V: 'v',
- Key.Key_W: 'w',
- Key.Key_X: 'x',
- Key.Key_Y: 'y',
- Key.Key_Z: 'z',
- Key.Key_Asterisk: 'asterisk',
- Key.Key_Plus: 'plus',
- Key.Key_Minus: 'minus',
- Key.Key_Period: 'period',
- Key.Key_Slash: 'slash',
- Key.Key_F1: 'F1',
- Key.Key_F2: 'F2',
- Key.Key_F3: 'F3',
- Key.Key_F4: 'F4',
- Key.Key_F5: 'F5',
- Key.Key_F6: 'F6',
- Key.Key_F7: 'F7',
- Key.Key_F8: 'F8',
- Key.Key_F9: 'F9',
- Key.Key_F10: 'F10',
- Key.Key_F11: 'F11',
- Key.Key_F12: 'F12',
- Key.Key_F13: 'F13',
- Key.Key_F14: 'F14',
- Key.Key_F15: 'F15',
- Key.Key_F16: 'F16',
- Key.Key_F17: 'F17',
- Key.Key_F18: 'F18',
- Key.Key_F19: 'F19',
- Key.Key_F20: 'F20',
- Key.Key_F21: 'F21',
- Key.Key_F22: 'F22',
- Key.Key_F23: 'F23',
- Key.Key_F24: 'F24',
- Key.Key_NumLock: 'Num_Lock',
- Key.Key_ScrollLock: 'Scroll_Lock',
- }
+ Key.Key_End: "End",
+ Key.Key_Home: "Home",
+ Key.Key_Left: "Left",
+ Key.Key_Up: "Up",
+ Key.Key_Right: "Right",
+ Key.Key_Down: "Down",
+ Key.Key_SysReq: "Snapshot",
+ Key.Key_Insert: "Insert",
+ Key.Key_Delete: "Delete",
+ Key.Key_Help: "Help",
+ Key.Key_0: "0",
+ Key.Key_1: "1",
+ Key.Key_2: "2",
+ Key.Key_3: "3",
+ Key.Key_4: "4",
+ Key.Key_5: "5",
+ Key.Key_6: "6",
+ Key.Key_7: "7",
+ Key.Key_8: "8",
+ Key.Key_9: "9",
+ Key.Key_A: "a",
+ Key.Key_B: "b",
+ Key.Key_C: "c",
+ Key.Key_D: "d",
+ Key.Key_E: "e",
+ Key.Key_F: "f",
+ Key.Key_G: "g",
+ Key.Key_H: "h",
+ Key.Key_I: "i",
+ Key.Key_J: "j",
+ Key.Key_K: "k",
+ Key.Key_L: "l",
+ Key.Key_M: "m",
+ Key.Key_N: "n",
+ Key.Key_O: "o",
+ Key.Key_P: "p",
+ Key.Key_Q: "q",
+ Key.Key_R: "r",
+ Key.Key_S: "s",
+ Key.Key_T: "t",
+ Key.Key_U: "u",
+ Key.Key_V: "v",
+ Key.Key_W: "w",
+ Key.Key_X: "x",
+ Key.Key_Y: "y",
+ Key.Key_Z: "z",
+ Key.Key_Asterisk: "asterisk",
+ Key.Key_Plus: "plus",
+ Key.Key_Minus: "minus",
+ Key.Key_Period: "period",
+ Key.Key_Slash: "slash",
+ Key.Key_F1: "F1",
+ Key.Key_F2: "F2",
+ Key.Key_F3: "F3",
+ Key.Key_F4: "F4",
+ Key.Key_F5: "F5",
+ Key.Key_F6: "F6",
+ Key.Key_F7: "F7",
+ Key.Key_F8: "F8",
+ Key.Key_F9: "F9",
+ Key.Key_F10: "F10",
+ Key.Key_F11: "F11",
+ Key.Key_F12: "F12",
+ Key.Key_F13: "F13",
+ Key.Key_F14: "F14",
+ Key.Key_F15: "F15",
+ Key.Key_F16: "F16",
+ Key.Key_F17: "F17",
+ Key.Key_F18: "F18",
+ Key.Key_F19: "F19",
+ Key.Key_F20: "F20",
+ Key.Key_F21: "F21",
+ Key.Key_F22: "F22",
+ Key.Key_F23: "F23",
+ Key.Key_F24: "F24",
+ Key.Key_NumLock: "Num_Lock",
+ Key.Key_ScrollLock: "Scroll_Lock",
+}
if __name__ == "__main__":
- print(PyQtImpl)
QVTKRenderWidgetConeExample()
diff --git a/pyvistaqt/utils.py b/pyvistaqt/utils.py
index f8c834a7..1b72fe98 100644
--- a/pyvistaqt/utils.py
+++ b/pyvistaqt/utils.py
@@ -1,23 +1,28 @@
-"""This module contains utilities routines."""
+"""This module contains utilities routines.""" # noqa: D404
-from typing import Any, List, Optional, Type
+from __future__ import annotations
+
+from typing import Any
+from typing import List
+from typing import Optional
+from typing import Type
import pyvista
-import scooby # type: ignore
-from qtpy.QtWidgets import QApplication, QMenuBar
+from qtpy.QtWidgets import QApplication
+from qtpy.QtWidgets import QMenuBar
+import scooby # type: ignore # noqa: PGH003
-def _check_type(var: Any, var_name: str, var_types: List[Type[Any]]) -> None:
+def _check_type(var: Any, var_name: str, var_types: List[Type[Any]]) -> None: # noqa: ANN401
types = tuple(var_types)
if not isinstance(var, types):
- raise TypeError(
- f"Expected type for ``{var_name}`` is {str(types)}"
- f" but {type(var)} was given."
- )
+ msg = f"Expected type for ``{var_name}`` is {types!s}" f" but {type(var)} was given."
+ raise TypeError(msg)
-def _create_menu_bar(parent: Any) -> QMenuBar:
- """Create a menu bar.
+def _create_menu_bar(parent: Any) -> QMenuBar: # noqa: ANN401
+ """
+ Create a menu bar.
The menu bar is expected to behave consistently
for every operating system since `setNativeMenuBar(False)`
@@ -31,7 +36,7 @@ def _create_menu_bar(parent: Any) -> QMenuBar:
return menu_bar
-def _setup_ipython(ipython: Any = None) -> Any:
+def _setup_ipython(ipython: Any = None) -> Any: # noqa: ANN401
# ipython magic
if scooby.in_ipython(): # pragma: no cover
# pylint: disable=import-outside-toplevel
diff --git a/pyvistaqt/window.py b/pyvistaqt/window.py
index 02e94e5c..86c698d4 100644
--- a/pyvistaqt/window.py
+++ b/pyvistaqt/window.py
@@ -1,10 +1,14 @@
-"""This module contains a Qt-compatible MainWindow class."""
+"""This module contains a Qt-compatible MainWindow class.""" # noqa: D404
-from typing import Optional, Tuple
+from __future__ import annotations
+
+from typing import Optional
+from typing import Tuple
from qtpy import QtCore
from qtpy.QtCore import Signal
-from qtpy.QtWidgets import QMainWindow, QWidget
+from qtpy.QtWidgets import QMainWindow
+from qtpy.QtWidgets import QWidget
class MainWindow(QMainWindow):
@@ -33,7 +37,7 @@ def event(self, event: QtCore.QEvent) -> bool:
return True
return super().event(event)
- def closeEvent(self, event: QtCore.QEvent) -> None: # pylint: disable=invalid-name
+ def closeEvent(self, event: QtCore.QEvent) -> None: # pylint: disable=invalid-name # noqa: N802
"""Manage the close event."""
self.signal_close.emit()
event.accept()
diff --git a/setup.py b/setup.py
index eac04777..ee46a0ee 100644
--- a/setup.py
+++ b/setup.py
@@ -1,51 +1,51 @@
-"""
-Installation file for python pyvistaqt module
-"""
+"""Installation file for python pyvistaqt module."""
+
+from __future__ import annotations
+
import os
from pathlib import Path
-from io import open as io_open
from setuptools import setup
-package_name = 'pyvistaqt'
-readme_file = Path(__file__).parent / 'README.rst'
+package_name = "pyvistaqt"
+readme_file = Path(__file__).parent / "README.rst"
setup(
name=package_name,
packages=[package_name, package_name],
- description='pyvista qt plotter',
+ description="pyvista qt plotter",
long_description=readme_file.read_text(),
- long_description_content_type='text/x-rst',
- author='PyVista Developers',
- author_email='info@pyvista.org',
- license='MIT',
+ long_description_content_type="text/x-rst",
+ author="PyVista Developers",
+ author_email="info@pyvista.org",
+ license="MIT",
classifiers=[
- 'Development Status :: 4 - Beta',
- 'Intended Audience :: Science/Research',
- 'Topic :: Scientific/Engineering :: Information Analysis',
- 'License :: OSI Approved :: MIT License',
- 'Operating System :: Microsoft :: Windows',
- 'Operating System :: POSIX',
- 'Operating System :: MacOS',
- 'Programming Language :: Python :: 3.7',
- 'Programming Language :: Python :: 3.8',
- 'Programming Language :: Python :: 3.9',
+ "Development Status :: 4 - Beta",
+ "Intended Audience :: Science/Research",
+ "Topic :: Scientific/Engineering :: Information Analysis",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: Microsoft :: Windows",
+ "Operating System :: POSIX",
+ "Operating System :: MacOS",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
],
-
- url='https://github.com/pyvista/pyvistaqt',
- keywords='vtk numpy plotting mesh qt',
- python_requires='>=3.7',
+ url="https://github.com/pyvista/pyvistaqt",
+ keywords="vtk numpy plotting mesh qt",
+ python_requires=">=3.7",
setup_requires=["setuptools>=45", "setuptools_scm>=6.2"],
use_scm_version={
"write_to": "pyvistaqt/_version.py",
"version_scheme": "release-branch-semver",
},
install_requires=[
- 'pyvista>=0.32.0',
- 'QtPy>=1.9.0',
+ "pyvista>=0.32.0",
+ "QtPy>=1.9.0",
],
- package_data={'pyvistaqt': [
- os.path.join('data', '*.png'),
- ]}
-
+ package_data={
+ "pyvistaqt": [
+ os.path.join("data", "*.png"), # noqa: PTH118
+ ]
+ },
)
diff --git a/tests/__init__.py b/tests/__init__.py
index e69de29b..6e031999 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -0,0 +1 @@
+# noqa: D104
diff --git a/tests/conftest.py b/tests/conftest.py
index 3c3fdefe..274edc4a 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,3 +1,5 @@
+from __future__ import annotations # noqa: D100
+
import gc
import importlib
import inspect
@@ -6,117 +8,110 @@
import pytest
import pyvista
from pyvista.plotting import system_supports_plotting
+
import pyvistaqt
NO_PLOTTING = not system_supports_plotting()
-def pytest_configure(config):
+def pytest_configure(config) -> None:
"""Configure pytest options."""
# Fixtures
- for fixture in ('check_gc',):
- config.addinivalue_line('usefixtures', fixture)
+ for fixture in ("check_gc",):
+ config.addinivalue_line("usefixtures", fixture)
# Markers
- for marker in ('allow_bad_gc', 'allow_bad_gc_pyside'):
- config.addinivalue_line('markers', marker)
+ for marker in ("allow_bad_gc", "allow_bad_gc_pyside"):
+ config.addinivalue_line("markers", marker)
# Adapted from PyVista
-def _is_vtk(obj):
+def _is_vtk(obj): # noqa: ANN202
try:
- return obj.__class__.__name__.startswith('vtk')
- except Exception: # old Python sometimes no __class__.__name__
+ return obj.__class__.__name__.startswith("vtk")
+ except Exception: # old Python sometimes no __class__.__name__ # noqa: BLE001
return False
-def _check_qt_installed():
+def _check_qt_installed() -> bool:
try:
- from qtpy import QtCore # noqa
- except Exception:
+ from qtpy import QtCore # noqa: F401
+ except Exception: # noqa: BLE001
return False
else:
return True
@pytest.fixture(autouse=True)
-def check_gc(request):
+def check_gc(request): # noqa: ANN201, C901
"""Ensure that all VTK objects are garbage-collected by Python."""
- if 'test_ipython' in request.node.name: # XXX this keeps a ref
+ if "test_ipython" in request.node.name: # XXX this keeps a ref # noqa: FIX003, TD001, TD002, TD003, TD004
yield
return
try:
from qtpy import API_NAME
- except Exception:
- API_NAME = ''
- marks = set(mark.name for mark in request.node.iter_markers())
- if 'allow_bad_gc' in marks:
+ except Exception: # noqa: BLE001
+ API_NAME = "" # noqa: N806
+ marks = {mark.name for mark in request.node.iter_markers()}
+ if "allow_bad_gc" in marks:
yield
return
- if 'allow_bad_gc_pyside' in marks and API_NAME.lower().startswith('pyside'):
+ if "allow_bad_gc_pyside" in marks and API_NAME.lower().startswith("pyside"):
yield
return
gc.collect()
- before = set(id(o) for o in gc.get_objects() if _is_vtk(o))
+ before = {id(o) for o in gc.get_objects() if _is_vtk(o)}
yield
pyvista.close_all()
gc.collect()
- after = [
- o
- for o in gc.get_objects()
- if _is_vtk(o) and id(o) not in before
- ]
- msg = 'Not all objects GCed:\n'
+ after = [o for o in gc.get_objects() if _is_vtk(o) and id(o) not in before]
+ msg = "Not all objects GCed:\n"
for obj in after:
cn = obj.__class__.__name__
cf = inspect.currentframe()
- referrers = [
- v for v in gc.get_referrers(obj)
- if v is not after and v is not cf
- ]
+ referrers = [v for v in gc.get_referrers(obj) if v is not after and v is not cf]
del cf
for ri, referrer in enumerate(referrers):
if isinstance(referrer, dict):
for k, v in referrer.items():
if k is obj:
- referrers[ri] = 'dict: d key'
+ referrers[ri] = "dict: d key"
del k, v
break
elif v is obj:
- referrers[ri] = f'dict: d[{k!r}]'
- #raise RuntimeError(referrers[ri])
+ referrers[ri] = f"dict: d[{k!r}]"
+ # raise RuntimeError(referrers[ri]) # noqa: ERA001
del k, v
break
del k, v
else:
- referrers[ri] = f'dict: len={len(referrer)}'
+ referrers[ri] = f"dict: len={len(referrer)}"
else:
referrers[ri] = repr(referrer)
del ri, referrer
- msg += f'{cn}: {referrers}\n'
+ msg += f"{cn}: {referrers}\n"
del cn, referrers
assert len(after) == 0, msg
-@pytest.fixture()
-def plotting():
+@pytest.fixture
+def plotting() -> None:
"""Require plotting."""
if NO_PLOTTING:
pytest.skip(NO_PLOTTING, reason="Requires system to support plotting")
- yield
-@pytest.fixture()
-def no_qt(monkeypatch):
+@pytest.fixture
+def no_qt(monkeypatch): # noqa: ANN201
"""Require plotting."""
need_reload = False
if _check_qt_installed():
need_reload = True
- monkeypatch.setenv('QT_API', 'bad_name')
- sys.modules.pop('qtpy')
+ monkeypatch.setenv("QT_API", "bad_name")
+ sys.modules.pop("qtpy")
importlib.reload(pyvistaqt)
- assert 'qtpy' not in sys.modules
+ assert "qtpy" not in sys.modules
yield
monkeypatch.undo()
if need_reload:
importlib.reload(pyvistaqt)
- assert 'qtpy' in sys.modules
+ assert "qtpy" in sys.modules
diff --git a/tests/test_plotting.py b/tests/test_plotting.py
index 3614d796..f1b19009 100644
--- a/tests/test_plotting.py
+++ b/tests/test_plotting.py
@@ -1,42 +1,64 @@
+from __future__ import annotations # noqa: D100
+
from contextlib import nullcontext
import os
import os.path as op
-from packaging.version import Version
import platform
import re
import sys
import weakref
import numpy as np
+from packaging.version import Version
import pytest
import pyvista
-import vtk
-from qtpy.QtWidgets import QAction, QFrame, QMenuBar, QToolBar, QVBoxLayout
+from pyvista.plotting import Renderer
from qtpy import QtCore
-from qtpy.QtCore import Qt, QPoint, QPointF, QMimeData, QUrl
-from qtpy.QtGui import QDragEnterEvent, QDropEvent
-from qtpy.QtWidgets import (QTreeWidget, QStackedWidget, QCheckBox,
- QGestureEvent, QPinchGesture)
+from qtpy.QtCore import QMimeData
+from qtpy.QtCore import QPoint
+from qtpy.QtCore import QPointF
+from qtpy.QtCore import Qt
+from qtpy.QtCore import QUrl
+from qtpy.QtGui import QDragEnterEvent
+from qtpy.QtGui import QDropEvent
+from qtpy.QtWidgets import QAction
+from qtpy.QtWidgets import QCheckBox
+from qtpy.QtWidgets import QFrame
+from qtpy.QtWidgets import QGestureEvent
+from qtpy.QtWidgets import QMenuBar
+from qtpy.QtWidgets import QPinchGesture
+from qtpy.QtWidgets import QStackedWidget
+from qtpy.QtWidgets import QToolBar
+from qtpy.QtWidgets import QTreeWidget
+from qtpy.QtWidgets import QVBoxLayout
+import vtk
+
from pyvistaqt.plotting import global_theme
-from pyvista.plotting import Renderer
+
try:
from pyvista.plotting.utilities import Scraper
except ImportError: # PV < 0.40
from pyvista.utilities import Scraper
import pyvistaqt
-from pyvistaqt import MultiPlotter, BackgroundPlotter, MainWindow, QtInteractor
-from pyvistaqt.plotting import Counter, QTimer, QVTKRenderWindowInteractor
-from pyvistaqt.editor import Editor
+from pyvistaqt import BackgroundPlotter
+from pyvistaqt import MainWindow
+from pyvistaqt import MultiPlotter
+from pyvistaqt import QtInteractor
from pyvistaqt.dialog import FileDialog
-from pyvistaqt.utils import _setup_application, _create_menu_bar, _check_type
-
+from pyvistaqt.editor import Editor
+from pyvistaqt.plotting import Counter
+from pyvistaqt.plotting import QTimer
+from pyvistaqt.plotting import QVTKRenderWindowInteractor
+from pyvistaqt.utils import _check_type
+from pyvistaqt.utils import _create_menu_bar
+from pyvistaqt.utils import _setup_application
PV_VERSION = Version(pyvista.__version__)
-class TstWindow(MainWindow):
- def __init__(self, parent=None, show=True, off_screen=True):
+class TstWindow(MainWindow): # noqa: D101
+ def __init__(self, parent=None, show=True, off_screen=True) -> None: # noqa: FBT002, D107
MainWindow.__init__(self, parent)
self.frame = QFrame()
@@ -51,17 +73,17 @@ def __init__(self, parent=None, show=True, off_screen=True):
self.frame.setLayout(vlayout)
self.setCentralWidget(self.frame)
- mainMenu = _create_menu_bar(parent=self)
+ mainMenu = _create_menu_bar(parent=self) # noqa: N806
- fileMenu = mainMenu.addMenu('File')
- self.exit_action = QAction('Exit', self)
- self.exit_action.setShortcut('Ctrl+Q')
+ fileMenu = mainMenu.addMenu("File") # noqa: N806
+ self.exit_action = QAction("Exit", self)
+ self.exit_action.setShortcut("Ctrl+Q")
self.exit_action.triggered.connect(self.close)
fileMenu.addAction(self.exit_action)
- meshMenu = mainMenu.addMenu('Mesh')
- self.add_sphere_action = QAction('Add Sphere', self)
- self.exit_action.setShortcut('Ctrl+A')
+ meshMenu = mainMenu.addMenu("Mesh") # noqa: N806
+ self.add_sphere_action = QAction("Add Sphere", self)
+ self.exit_action.setShortcut("Ctrl+A")
self.add_sphere_action.triggered.connect(self.add_sphere)
meshMenu.addAction(self.add_sphere_action)
@@ -70,25 +92,22 @@ def __init__(self, parent=None, show=True, off_screen=True):
if show:
self.show()
- def add_sphere(self):
- sphere = pyvista.Sphere(
- phi_resolution=6,
- theta_resolution=6
- )
+ def add_sphere(self) -> None: # noqa: D102
+ sphere = pyvista.Sphere(phi_resolution=6, theta_resolution=6)
self.vtk_widget.add_mesh(sphere)
self.vtk_widget.reset_camera()
-def test_create_menu_bar(qtbot):
+def test_create_menu_bar(qtbot) -> None: # noqa: D103
menu_bar = _create_menu_bar(parent=None)
qtbot.addWidget(menu_bar)
-def test_setup_application(qapp):
+def test_setup_application(qapp) -> None: # noqa: D103
_setup_application(qapp)
-def test_file_dialog(tmpdir, qtbot):
+def test_file_dialog(tmpdir, qtbot) -> None: # noqa: D103
dialog = FileDialog(
filefilter=None,
directory=False,
@@ -100,8 +119,8 @@ def test_file_dialog(tmpdir, qtbot):
dialog.emit_accepted() # test no result
p = tmpdir.mkdir("tmp").join("foo.png")
- p.write('foo')
- assert os.path.isfile(p)
+ p.write("foo")
+ assert os.path.isfile(p) # noqa: PTH113
filename = str(p)
dialog.selectFile(filename)
@@ -118,14 +137,14 @@ def test_file_dialog(tmpdir, qtbot):
assert not dialog.isVisible() # dialog is closed after accept()
-def test_check_type():
+def test_check_type() -> None: # noqa: D103
with pytest.raises(TypeError, match="Expected type"):
_check_type(0, "foo", [str])
_check_type(0, "foo", [int, float])
_check_type("foo", "foo", [str])
-def test_mouse_interactions(qtbot):
+def test_mouse_interactions(qtbot) -> None: # noqa: D103
plotter = BackgroundPlotter()
window = plotter.app_window
interactor = plotter.interactor
@@ -136,19 +155,18 @@ def test_mouse_interactions(qtbot):
plotter.close()
-@pytest.mark.skipif(platform.system()=="Windows" and platform.python_version()[:-1]=="3.8.", reason="#51")
-def test_ipython(qapp):
- IPython = pytest.importorskip('IPython')
- cmd = "from pyvistaqt import BackgroundPlotter as Plotter;" \
- "p = Plotter(show=False, off_screen=False); p.close(); exit()"
+@pytest.mark.skipif(platform.system() == "Windows" and platform.python_version()[:-1] == "3.8.", reason="#51")
+def test_ipython(qapp) -> None: # noqa: ARG001, D103
+ IPython = pytest.importorskip("IPython") # noqa: N806
+ cmd = "from pyvistaqt import BackgroundPlotter as Plotter;" "p = Plotter(show=False, off_screen=False); p.close(); exit()"
IPython.start_ipython(argv=["-c", cmd])
-class SuperWindow(MainWindow):
+class SuperWindow(MainWindow): # noqa: D101
pass
-def test_depth_peeling(qtbot):
+def test_depth_peeling(qtbot) -> None: # noqa: D103
plotter = BackgroundPlotter()
qtbot.addWidget(plotter.app_window)
assert not plotter.renderer.GetUseDepthPeeling()
@@ -163,7 +181,7 @@ def test_depth_peeling(qtbot):
global_theme.depth_peeling["enabled"] = False
-def test_off_screen(qtbot):
+def test_off_screen(qtbot) -> None: # noqa: D103
plotter = BackgroundPlotter(off_screen=False)
qtbot.addWidget(plotter.app_window)
assert not plotter.ren_win.GetOffScreenRendering()
@@ -174,7 +192,7 @@ def test_off_screen(qtbot):
plotter.close()
-def test_smoothing(qtbot):
+def test_smoothing(qtbot) -> None: # noqa: D103
plotter = BackgroundPlotter()
qtbot.addWidget(plotter.app_window)
assert not plotter.ren_win.GetPolygonSmoothing()
@@ -193,10 +211,10 @@ def test_smoothing(qtbot):
plotter.close()
-def test_counter(qtbot):
- with pytest.raises(TypeError, match='type of'):
+def test_counter(qtbot) -> None: # noqa: D103
+ with pytest.raises(TypeError, match="type of"):
Counter(count=0.5)
- with pytest.raises(ValueError, match='strictly positive'):
+ with pytest.raises(ValueError, match="strictly positive"):
Counter(count=-1)
counter = Counter(count=1)
@@ -206,15 +224,15 @@ def test_counter(qtbot):
assert counter.count == 0
-# TODO: Fix gc on PySide6
-@pytest.mark.parametrize('border', (True, False))
+# TODO: Fix gc on PySide6 # noqa: FIX002, TD002, TD003
+@pytest.mark.parametrize("border", [True, False])
@pytest.mark.allow_bad_gc_pyside
-def test_subplot_gc(border):
+def test_subplot_gc(border) -> None: # noqa: D103
BackgroundPlotter(shape=(2, 1), update_app_icon=False, border=border)
@pytest.mark.allow_bad_gc_pyside
-def test_editor(qtbot, plotting):
+def test_editor(qtbot, plotting) -> None: # noqa: ARG001, D103
# test editor=False
plotter = BackgroundPlotter(editor=False, off_screen=False)
qtbot.addWidget(plotter.app_window)
@@ -280,22 +298,23 @@ def test_editor(qtbot, plotting):
plotter.close()
-@pytest.fixture()
-def ensure_closed():
+@pytest.fixture
+def ensure_closed(): # noqa: ANN201
"""Ensure all plotters are closed."""
try:
from pyvista.plotting import close_all
from pyvista.plotting.plotter import _ALL_PLOTTERS
except ImportError: # PV < 0.40
- from pyvista.plotting.plotting import _ALL_PLOTTERS, close_all
+ from pyvista.plotting.plotting import _ALL_PLOTTERS
+ from pyvista.plotting.plotting import close_all
close_all() # this is necessary to test _ALL_PLOTTERS
assert len(_ALL_PLOTTERS) == 0
yield
- WANT_AFTER = 0 if PV_VERSION >= Version('0.37') else 1
+ WANT_AFTER = 0 if Version("0.37") <= PV_VERSION else 1 # noqa: N806
assert len(_ALL_PLOTTERS) == WANT_AFTER
-def test_qt_interactor(qtbot, plotting, ensure_closed):
+def test_qt_interactor(qtbot, plotting, ensure_closed) -> None: # noqa: ARG001, D103
window = TstWindow(show=False, off_screen=False)
qtbot.addWidget(window) # register the main widget
@@ -332,7 +351,7 @@ def test_qt_interactor(qtbot, plotting, ensure_closed):
assert window.isVisible()
assert interactor.isVisible()
assert render_timer.isActive()
- assert not vtk_widget._closed
+ assert not vtk_widget._closed # noqa: SLF001
# test enable/disable interactivity
vtk_widget.disable()
@@ -347,21 +366,20 @@ def test_qt_interactor(qtbot, plotting, ensure_closed):
assert not render_timer.isActive()
# check that BasePlotter.close() is called
- if Version(pyvista.__version__) < Version('0.27.0'):
+ if Version(pyvista.__version__) < Version("0.27.0"):
assert not hasattr(vtk_widget, "iren")
- assert vtk_widget._closed
-
-
-@pytest.mark.parametrize('show_plotter', [
- True,
- False,
- ])
-def test_background_plotting_axes_scale(qtbot, show_plotter, plotting):
- plotter = BackgroundPlotter(
- show=show_plotter,
- off_screen=False,
- title='Testing Window'
- )
+ assert vtk_widget._closed # noqa: SLF001
+
+
+@pytest.mark.parametrize(
+ "show_plotter",
+ [
+ True,
+ False,
+ ],
+)
+def test_background_plotting_axes_scale(qtbot, show_plotter, plotting) -> None: # noqa: ARG001, D103
+ plotter = BackgroundPlotter(show=show_plotter, off_screen=False, title="Testing Window")
assert_hasattr(plotter, "app_window", MainWindow)
window = plotter.app_window # MainWindow
qtbot.addWidget(window) # register the window
@@ -376,7 +394,7 @@ def test_background_plotting_axes_scale(qtbot, show_plotter, plotting):
plotter.add_mesh(pyvista.Sphere())
assert_hasattr(plotter, "renderer", Renderer)
renderer = plotter.renderer
- assert len(renderer._actors) == 1
+ assert len(renderer._actors) == 1 # noqa: SLF001
assert np.any(plotter.mesh.points)
dlg = plotter.scale_axes_dialog(show=False) # ScaleAxesDialog
@@ -394,9 +412,9 @@ def test_background_plotting_axes_scale(qtbot, show_plotter, plotting):
dlg.x_slider_group.spinbox.setValue(-1)
assert dlg.x_slider_group.value == 0
dlg.x_slider_group.spinbox.setValue(1000.0)
- assert dlg.x_slider_group.value < 100
+ assert dlg.x_slider_group.value < 100 # noqa: PLR2004
- plotter._last_update_time = 0.0
+ plotter._last_update_time = 0.0 # noqa: SLF001
plotter.update()
plotter.update_app_icon()
plotter.close()
@@ -404,8 +422,8 @@ def test_background_plotting_axes_scale(qtbot, show_plotter, plotting):
assert not dlg.isVisible()
-def test_background_plotting_camera(qtbot, plotting):
- plotter = BackgroundPlotter(off_screen=False, title='Testing Window')
+def test_background_plotting_camera(qtbot, plotting) -> None: # noqa: ARG001, D103
+ plotter = BackgroundPlotter(off_screen=False, title="Testing Window")
plotter.add_mesh(pyvista.Sphere())
cpos = [(0.0, 0.0, 1.0), (0.0, 0.0, 0.0), (0.0, 1.0, 0.0)]
@@ -420,20 +438,19 @@ def test_background_plotting_camera(qtbot, plotting):
plotter.clear_camera_positions()
# 2 because the first two buttons are save and clear
- assert len(plotter.saved_cameras_tool_bar.actions()) == 2
+ assert len(plotter.saved_cameras_tool_bar.actions()) == 2 # noqa: PLR2004
plotter.close()
-@pytest.mark.parametrize('other_views', [None, 0, [0]])
-def test_link_views_across_plotters(other_views):
-
- def _to_array(camera_position):
+@pytest.mark.parametrize("other_views", [None, 0, [0]])
+def test_link_views_across_plotters(other_views) -> None: # noqa: D103
+ def _to_array(camera_position): # noqa: ANN202
return np.asarray([list(row) for row in camera_position])
- plotter_one = BackgroundPlotter(off_screen=True, title='Testing Window')
+ plotter_one = BackgroundPlotter(off_screen=True, title="Testing Window")
plotter_one.add_mesh(pyvista.Sphere())
- plotter_two = BackgroundPlotter(off_screen=True, title='Testing Window')
+ plotter_two = BackgroundPlotter(off_screen=True, title="Testing Window")
plotter_two.add_mesh(pyvista.Sphere())
plotter_one.link_views_across_plotters(plotter_two, other_views=other_views)
@@ -459,25 +476,24 @@ def _to_array(camera_position):
_to_array(plotter_two.camera_position),
)
- match = 'Expected `other_views` type is int, or list or tuple of ints, but float64 is given'
+ match = "Expected `other_views` type is int, or list or tuple of ints, but float64 is given"
with pytest.raises(TypeError, match=match):
plotter_one.link_views_across_plotters(plotter_two, other_views=[0.0])
-@pytest.mark.parametrize('show_plotter', [
- True,
- False,
- ])
-def test_background_plotter_export_files(qtbot, tmpdir, show_plotter, plotting):
+@pytest.mark.parametrize(
+ "show_plotter",
+ [
+ True,
+ False,
+ ],
+)
+def test_background_plotter_export_files(qtbot, tmpdir, show_plotter, plotting) -> None: # noqa: ARG001, D103
# setup filesystem
output_dir = str(tmpdir.mkdir("tmpdir"))
- assert os.path.isdir(output_dir)
+ assert os.path.isdir(output_dir) # noqa: PTH112
- plotter = BackgroundPlotter(
- show=show_plotter,
- off_screen=False,
- title='Testing Window'
- )
+ plotter = BackgroundPlotter(show=show_plotter, off_screen=False, title="Testing Window")
assert_hasattr(plotter, "app_window", MainWindow)
window = plotter.app_window # MainWindow
qtbot.addWidget(window) # register the window
@@ -492,13 +508,13 @@ def test_background_plotter_export_files(qtbot, tmpdir, show_plotter, plotting):
plotter.add_mesh(pyvista.Sphere())
assert_hasattr(plotter, "renderer", Renderer)
renderer = plotter.renderer
- assert len(renderer._actors) == 1
+ assert len(renderer._actors) == 1 # noqa: SLF001
assert np.any(plotter.mesh.points)
- dlg = plotter._qt_screenshot(show=False) # FileDialog
+ dlg = plotter._qt_screenshot(show=False) # FileDialog # noqa: SLF001
qtbot.addWidget(dlg) # register the dialog
- filename = str(os.path.join(output_dir, "tmp.png"))
+ filename = str(os.path.join(output_dir, "tmp.png")) # noqa: PTH118
dlg.selectFile(filename)
# show the dialog
@@ -514,21 +530,17 @@ def test_background_plotter_export_files(qtbot, tmpdir, show_plotter, plotting):
plotter.close()
assert not window.isVisible()
- assert os.path.isfile(filename)
+ assert os.path.isfile(filename) # noqa: PTH113
@pytest.mark.skip
@pytest.mark.allow_bad_gc
-def test_background_plotter_export_vtkjs(qtbot, tmpdir, plotting):
+def test_background_plotter_export_vtkjs(qtbot, tmpdir, plotting) -> None: # noqa: ARG001, D103
# setup filesystem
output_dir = str(tmpdir.mkdir("tmpdir"))
- assert os.path.isdir(output_dir)
+ assert os.path.isdir(output_dir) # noqa: PTH112
- plotter = BackgroundPlotter(
- show=False,
- off_screen=False,
- title='Testing Window'
- )
+ plotter = BackgroundPlotter(show=False, off_screen=False, title="Testing Window")
assert_hasattr(plotter, "app_window", MainWindow)
window = plotter.app_window # MainWindow
qtbot.addWidget(window) # register the window
@@ -543,18 +555,18 @@ def test_background_plotter_export_vtkjs(qtbot, tmpdir, plotting):
plotter.add_mesh(pyvista.Sphere())
assert_hasattr(plotter, "renderer", Renderer)
renderer = plotter.renderer
- assert len(renderer._actors) == 1
+ assert len(renderer._actors) == 1 # noqa: SLF001
assert np.any(plotter.mesh.points)
- dlg = plotter._qt_export_vtkjs(show=False) # FileDialog
+ dlg = plotter._qt_export_vtkjs(show=False) # FileDialog # noqa: SLF001
qtbot.addWidget(dlg) # register the dialog
- if hasattr(plotter, 'export_vtksz'):
- ext = '.vtksz'
- filename = str(os.path.join(output_dir, f"tmp{ext}"))
+ if hasattr(plotter, "export_vtksz"):
+ ext = ".vtksz"
+ filename = str(os.path.join(output_dir, f"tmp{ext}")) # noqa: PTH118
else:
- ext = '.vtkjs'
- filename = str(os.path.join(output_dir, f"tmp"))
+ ext = ".vtkjs"
+ filename = str(os.path.join(output_dir, "tmp")) # noqa: PTH118
dlg.selectFile(filename)
# show the dialog
@@ -571,17 +583,17 @@ def test_background_plotter_export_vtkjs(qtbot, tmpdir, plotting):
plotter.close()
assert not window.isVisible()
- if hasattr(plotter, 'export_vtksz'):
- assert os.path.isfile(filename)
+ if hasattr(plotter, "export_vtksz"):
+ assert os.path.isfile(filename) # noqa: PTH113
else:
- assert os.path.isfile(filename + ext)
+ assert os.path.isfile(filename + ext) # noqa: PTH113
# vtkWeakReference and vtkFloatArray, only sometimes -- usually PySide2
# but also sometimes macOS
@pytest.mark.allow_bad_gc
-def test_background_plotting_orbit(qtbot, plotting):
- plotter = BackgroundPlotter(off_screen=False, title='Testing Window')
+def test_background_plotting_orbit(qtbot, plotting) -> None: # noqa: ARG001, D103
+ plotter = BackgroundPlotter(off_screen=False, title="Testing Window")
plotter.add_mesh(pyvista.Sphere())
# perform the orbit:
plotter.orbit_on_path(threaded=True, step=0.0)
@@ -589,8 +601,8 @@ def test_background_plotting_orbit(qtbot, plotting):
@pytest.mark.skipif(sys.version_info < (3, 10), reason="#508")
-def test_background_plotting_toolbar(qtbot, plotting):
- with pytest.raises(TypeError, match='toolbar'):
+def test_background_plotting_toolbar(qtbot, plotting) -> None: # noqa: ARG001, D103
+ with pytest.raises(TypeError, match="toolbar"): # noqa: PT012
p = BackgroundPlotter(off_screen=False, toolbar="foo")
p.close()
@@ -618,26 +630,24 @@ def test_background_plotting_toolbar(qtbot, plotting):
assert saved_cameras_tool_bar.isVisible()
# triggering a view action
- plotter._view_action.trigger()
+ plotter._view_action.trigger() # noqa: SLF001
plotter.close()
-# TODO: _render_passes not GC'ed
+# TODO: _render_passes not GC'ed # noqa: FIX002, TD002, TD003
@pytest.mark.allow_bad_gc_pyside
-@pytest.mark.skipif(
- platform.system() == 'Windows', reason='Segfaults on Windows')
-def test_background_plotting_menu_bar(qtbot, plotting):
- with pytest.raises(TypeError, match='menu_bar'):
+@pytest.mark.skipif(platform.system() == "Windows", reason="Segfaults on Windows")
+def test_background_plotting_menu_bar(qtbot, plotting) -> None: # noqa: ARG001, D103
+ with pytest.raises(TypeError, match="menu_bar"):
BackgroundPlotter(off_screen=False, menu_bar="foo")
- plotter = BackgroundPlotter(
- off_screen=False, menu_bar=False, update_app_icon=False)
+ plotter = BackgroundPlotter(off_screen=False, menu_bar=False, update_app_icon=False)
assert plotter.main_menu is None
- assert plotter._menu_close_action is None
+ assert plotter._menu_close_action is None # noqa: SLF001
plotter.close()
- # menu_bar=True
+ # menu_bar=True # noqa: ERA001
plotter = BackgroundPlotter(off_screen=False, update_app_icon=False)
assert_hasattr(plotter, "app_window", MainWindow)
@@ -654,35 +664,35 @@ def test_background_plotting_menu_bar(qtbot, plotting):
window.show()
# EDL action
- if hasattr(plotter.renderer, '_render_passes'):
- obj, attr = plotter.renderer._render_passes, '_edl_pass'
+ if hasattr(plotter.renderer, "_render_passes"):
+ obj, attr = plotter.renderer._render_passes, "_edl_pass" # noqa: SLF001
else:
- obj, attr = plotter.renderer, 'edl_pass'
+ obj, attr = plotter.renderer, "edl_pass"
assert getattr(obj, attr, None) is None
- plotter._edl_action.trigger()
+ plotter._edl_action.trigger() # noqa: SLF001
assert getattr(obj, attr, None) is not None
# and now test reset
- plotter._edl_action.trigger()
+ plotter._edl_action.trigger() # noqa: SLF001
# Parallel projection action
assert not plotter.camera.GetParallelProjection()
- plotter._parallel_projection_action.trigger()
+ plotter._parallel_projection_action.trigger() # noqa: SLF001
assert plotter.camera.GetParallelProjection()
# and now test reset
- plotter._parallel_projection_action.trigger()
+ plotter._parallel_projection_action.trigger() # noqa: SLF001
assert main_menu.isVisible()
plotter.close()
assert not main_menu.isVisible()
- assert plotter._last_update_time == -np.inf
+ assert plotter._last_update_time == -np.inf # noqa: SLF001
-def test_drop_event(tmpdir, qtbot):
+def test_drop_event(tmpdir, qtbot) -> None: # noqa: D103
output_dir = str(tmpdir.mkdir("tmpdir"))
- filename = str(os.path.join(output_dir, "tmp.vtk"))
+ filename = str(os.path.join(output_dir, "tmp.vtk")) # noqa: PTH118
mesh = pyvista.Cone()
mesh.save(filename)
- assert os.path.isfile(filename)
+ assert os.path.isfile(filename) # noqa: PTH113
plotter = BackgroundPlotter(update_app_icon=False)
with qtbot.wait_exposed(plotter.app_window, timeout=10000):
plotter.app_window.show()
@@ -700,12 +710,12 @@ def test_drop_event(tmpdir, qtbot):
plotter.close()
-def test_drag_event(tmpdir):
+def test_drag_event(tmpdir) -> None: # noqa: D103
output_dir = str(tmpdir.mkdir("tmpdir"))
- filename = str(os.path.join(output_dir, "tmp.vtk"))
+ filename = str(os.path.join(output_dir, "tmp.vtk")) # noqa: PTH118
mesh = pyvista.Cone()
mesh.save(filename)
- assert os.path.isfile(filename)
+ assert os.path.isfile(filename) # noqa: PTH113
plotter = BackgroundPlotter(update_app_icon=False)
point = QPoint(0, 0)
data = QMimeData()
@@ -721,7 +731,7 @@ def test_drag_event(tmpdir):
plotter.close()
-def test_gesture_event(qtbot):
+def test_gesture_event(qtbot) -> None: # noqa: D103
plotter = BackgroundPlotter(update_app_icon=False)
with qtbot.wait_exposed(plotter.app_window, timeout=10000):
plotter.app_window.show()
@@ -731,38 +741,38 @@ def test_gesture_event(qtbot):
plotter.close()
-def test_background_plotting_add_callback(qtbot, monkeypatch, plotting):
- class CallBack(object):
- def __init__(self, sphere):
+def test_background_plotting_add_callback(qtbot, monkeypatch, plotting) -> None: # noqa: ARG001, D103
+ class CallBack:
+ def __init__(self, sphere) -> None:
self.sphere = weakref.ref(sphere)
- def __call__(self):
+ def __call__(self): # noqa: ANN204
self.sphere().points[:] = self.sphere().points * 0.5
update_count = [0]
orig_update_app_icon = BackgroundPlotter.update_app_icon
- def update_app_icon(slf):
+ def update_app_icon(slf): # noqa: ANN202
update_count[0] = update_count[0] + 1
return orig_update_app_icon(slf)
- monkeypatch.setattr(BackgroundPlotter, 'update_app_icon', update_app_icon)
+ monkeypatch.setattr(BackgroundPlotter, "update_app_icon", update_app_icon)
plotter = BackgroundPlotter(
show=False,
off_screen=False,
- title='Testing Window',
+ title="Testing Window",
update_app_icon=True, # also does add_callback
)
assert_hasattr(plotter, "app_window", MainWindow)
assert_hasattr(plotter, "_callback_timer", QTimer)
assert_hasattr(plotter, "counters", list)
- assert plotter._last_update_time == -np.inf
+ assert plotter._last_update_time == -np.inf # noqa: SLF001
sphere = pyvista.Sphere()
plotter.add_mesh(sphere)
mycallback = CallBack(sphere)
window = plotter.app_window # MainWindow
- callback_timer = plotter._callback_timer # QTimer
+ callback_timer = plotter._callback_timer # QTimer # noqa: SLF001
assert callback_timer.isActive()
# ensure that the window is showed
@@ -777,18 +787,16 @@ def update_app_icon(slf):
plotter.update_app_icon() # should be a no-op
assert update_count[0] in [2, 3]
with pytest.raises(ValueError, match="ndarray with shape"):
- plotter.set_icon(0.)
+ plotter.set_icon(0.0)
# Maybe someday manually setting "set_icon" should disable update_app_icon?
# Strings also supported directly by QIcon
- plotter.set_icon(os.path.join(
- os.path.dirname(pyvistaqt.__file__), "data",
- "pyvista_logo_square.png"))
+ plotter.set_icon(os.path.join(os.path.dirname(pyvistaqt.__file__), "data", "pyvista_logo_square.png")) # noqa: PTH118, PTH120
callback_timer.stop()
assert not callback_timer.isActive()
# check that timers are set properly in add_callback()
plotter.add_callback(mycallback, interval=200, count=3)
- callback_timer = plotter._callback_timer # QTimer
+ callback_timer = plotter._callback_timer # QTimer # noqa: SLF001
assert callback_timer.isActive()
counter = plotter.counters[-1] # Counter
@@ -801,7 +809,7 @@ def update_app_icon(slf):
assert not callback_timer.isActive() # counter stops the callback
plotter.add_callback(mycallback, interval=200)
- callback_timer = plotter._callback_timer # QTimer
+ callback_timer = plotter._callback_timer # QTimer # noqa: SLF001
assert callback_timer.isActive()
# ensure that self.callback_timer send a signal
@@ -812,32 +820,36 @@ def update_app_icon(slf):
assert not callback_timer.isActive() # window stops the callback
-def allow_bad_gc_old_pyvista(func):
- if Version(pyvista.__version__) < Version('0.37'):
+def allow_bad_gc_old_pyvista(func): # noqa: ANN201, D103
+ if Version(pyvista.__version__) < Version("0.37"):
return pytest.mark.allow_bad_gc(func)
- else:
- return func
+ return func
-# TODO: Need to fix this allow_bad_gc:
+# TODO: Need to fix this allow_bad_gc: # noqa: FIX002, TD002, TD003
# - the actors are not cleaned up in the non-empty scene case
# - the q_key_press leaves a lingering vtkUnsignedCharArray referred to by
# a "managedbuffer" object
@allow_bad_gc_old_pyvista
@pytest.mark.allow_bad_gc_pyside
-@pytest.mark.parametrize('close_event', [
- "plotter_close",
- "window_close",
- pytest.param("q_key_press", marks=pytest.mark.allow_bad_gc),
- "menu_exit",
- "del_finalizer",
- ])
-@pytest.mark.parametrize('empty_scene', [
- True,
- False,
- ])
-def test_background_plotting_close(qtbot, close_event, empty_scene, plotting,
- ensure_closed):
+@pytest.mark.parametrize(
+ "close_event",
+ [
+ "plotter_close",
+ "window_close",
+ pytest.param("q_key_press", marks=pytest.mark.allow_bad_gc),
+ "menu_exit",
+ "del_finalizer",
+ ],
+)
+@pytest.mark.parametrize(
+ "empty_scene",
+ [
+ True,
+ False,
+ ],
+)
+def test_background_plotting_close(qtbot, close_event, empty_scene, plotting, ensure_closed) -> None: # noqa: ARG001, D103
plotter = _create_testing_scene(empty_scene)
# check that BackgroundPlotter.__init__() is called
@@ -874,7 +886,7 @@ def test_background_plotting_close(qtbot, close_event, empty_scene, plotting,
assert interactor.isVisible()
assert main_menu.isVisible()
assert render_timer.isActive()
- assert not plotter._closed
+ assert not plotter._closed # noqa: SLF001
with qtbot.wait_signals([window.signal_close], timeout=500):
if close_event == "plotter_close":
@@ -884,7 +896,7 @@ def test_background_plotting_close(qtbot, close_event, empty_scene, plotting,
elif close_event == "q_key_press":
qtbot.keyClick(interactor, "q")
elif close_event == "menu_exit":
- plotter._menu_close_action.trigger()
+ plotter._menu_close_action.trigger() # noqa: SLF001
elif close_event == "del_finalizer":
plotter.__del__()
@@ -895,43 +907,43 @@ def test_background_plotting_close(qtbot, close_event, empty_scene, plotting,
assert not render_timer.isActive()
# check that BasePlotter.close() is called
- if Version(pyvista.__version__) < Version('0.27.0'):
+ if Version(pyvista.__version__) < Version("0.27.0"):
assert not hasattr(window.vtk_widget, "iren")
- assert plotter._closed
+ assert plotter._closed # noqa: SLF001
-def test_multiplotter(qtbot, plotting):
+def test_multiplotter(qtbot, plotting) -> None: # noqa: ARG001, D103
mp = MultiPlotter(
nrows=1,
ncols=2,
window_size=(300, 300),
show=False,
- title='Test',
+ title="Test",
off_screen=False,
)
- qtbot.addWidget(mp._window)
+ qtbot.addWidget(mp._window) # noqa: SLF001
mp[0, 0].add_mesh(pyvista.Cone())
mp[0, 1].add_mesh(pyvista.Box())
- assert not mp._window.isVisible()
- with qtbot.wait_exposed(mp._window):
+ assert not mp._window.isVisible() # noqa: SLF001
+ with qtbot.wait_exposed(mp._window): # noqa: SLF001
mp.show()
- assert mp._window.isVisible()
- for p in mp._plotters:
- assert not p._closed
- with qtbot.wait_signals([mp._window.signal_close], timeout=1000):
+ assert mp._window.isVisible() # noqa: SLF001
+ for p in mp._plotters: # noqa: SLF001
+ assert not p._closed # noqa: SLF001
+ with qtbot.wait_signals([mp._window.signal_close], timeout=1000): # noqa: SLF001
mp.close()
- for p in mp._plotters:
- assert p._closed
+ for p in mp._plotters: # noqa: SLF001
+ assert p._closed # noqa: SLF001
# cover default show=True
mp = MultiPlotter(off_screen=False, menu_bar=False, toolbar=False)
- qtbot.addWidget(mp._window)
- with qtbot.wait_exposed(mp._window):
- assert mp._window.isVisible()
+ qtbot.addWidget(mp._window) # noqa: SLF001
+ with qtbot.wait_exposed(mp._window): # noqa: SLF001
+ assert mp._window.isVisible() # noqa: SLF001
mp.close()
-def _create_testing_scene(empty_scene, show=False, off_screen=False):
+def _create_testing_scene(empty_scene, show=False, off_screen=False): # noqa: ANN202, FBT002
if empty_scene:
plotter = BackgroundPlotter(
show=show,
@@ -943,92 +955,83 @@ def _create_testing_scene(empty_scene, show=False, off_screen=False):
shape=(2, 2),
border=True,
border_width=10,
- border_color='grey',
+ border_color="grey",
show=show,
off_screen=off_screen,
update_app_icon=False,
)
- plotter.set_background('black', top='blue')
+ plotter.set_background("black", top="blue")
plotter.subplot(0, 0)
cone = pyvista.Cone(resolution=4)
actor = plotter.add_mesh(cone)
plotter.remove_actor(actor)
- plotter.add_text('Actor is removed')
+ plotter.add_text("Actor is removed")
plotter.subplot(0, 1)
- plotter.add_mesh(pyvista.Box(), color='green', opacity=0.8)
+ plotter.add_mesh(pyvista.Box(), color="green", opacity=0.8)
plotter.subplot(1, 0)
cylinder = pyvista.Cylinder(resolution=6)
plotter.add_mesh(cylinder, smooth_shading=True)
plotter.show_bounds()
plotter.subplot(1, 1)
- sphere = pyvista.Sphere(
- phi_resolution=6,
- theta_resolution=6
- )
+ sphere = pyvista.Sphere(phi_resolution=6, theta_resolution=6)
plotter.add_mesh(sphere)
plotter.enable_cell_picking()
return plotter
-def assert_hasattr(variable, attribute_name, variable_type):
+def assert_hasattr(variable, attribute_name, variable_type) -> None: # noqa: D103
__tracebackhide__ = True
assert hasattr(variable, attribute_name)
assert isinstance(getattr(variable, attribute_name), variable_type)
-@pytest.mark.parametrize('n_win', [1, 2])
-def test_sphinx_gallery_scraping(qtbot, monkeypatch, plotting, tmpdir, n_win):
- pytest.importorskip('sphinx_gallery')
- if Version('0.38.0') <= PV_VERSION <= Version('0.38.6'):
- pytest.xfail('Scraping fails on PyVista 0.38.0 to 0.38.6')
- monkeypatch.setattr(pyvista, 'BUILDING_GALLERY', True)
+@pytest.mark.parametrize("n_win", [1, 2])
+def test_sphinx_gallery_scraping(qtbot, monkeypatch, plotting, tmpdir, n_win) -> None: # noqa: ARG001, D103
+ pytest.importorskip("sphinx_gallery")
+ if Version("0.38.0") <= PV_VERSION <= Version("0.38.6"):
+ pytest.xfail("Scraping fails on PyVista 0.38.0 to 0.38.6")
+ monkeypatch.setattr(pyvista, "BUILDING_GALLERY", True)
- plotters = [
- BackgroundPlotter(off_screen=False, editor=False, show=True)
- for _ in range(n_win)
- ]
+ plotters = [BackgroundPlotter(off_screen=False, editor=False, show=True) for _ in range(n_win)]
# Adapted from pyvista/tests/test_scraper.py
scraper = Scraper()
src_dir = str(tmpdir)
- out_dir = op.join(str(tmpdir), '_build', 'html')
- img_fnames = [
- op.join(src_dir, 'auto_examples', 'images', f'sg_img_{n}.png')
- for n in range(n_win)
- ]
+ out_dir = op.join(str(tmpdir), "_build", "html") # noqa: PTH118
+ img_fnames = [op.join(src_dir, "auto_examples", "images", f"sg_img_{n}.png") for n in range(n_win)] # noqa: PTH118
gallery_conf = {"src_dir": src_dir, "builder_name": "html"}
- target_file = op.join(src_dir, 'auto_examples', 'sg.py')
+ target_file = op.join(src_dir, "auto_examples", "sg.py") # noqa: PTH118
block = None
- block_vars = dict(
- image_path_iterator=(img for img in img_fnames),
- example_globals=dict(a=1),
- target_file=target_file,
- )
- os.makedirs(op.dirname(img_fnames[0]))
+ block_vars = {
+ "image_path_iterator": (img for img in img_fnames),
+ "example_globals": {"a": 1},
+ "target_file": target_file,
+ }
+ os.makedirs(op.dirname(img_fnames[0])) # noqa: PTH103, PTH120
for img_fname in img_fnames:
- assert not os.path.isfile(img_fname)
- os.makedirs(out_dir)
+ assert not os.path.isfile(img_fname) # noqa: PTH113
+ os.makedirs(out_dir) # noqa: PTH103
scraper(block, block_vars, gallery_conf)
for img_fname in img_fnames:
- assert os.path.isfile(img_fname)
+ assert os.path.isfile(img_fname) # noqa: PTH113
for plotter in plotters:
plotter.close()
@pytest.mark.skipif(sys.version_info < (3, 10), reason="#508")
-@pytest.mark.parametrize("aa", [
- False,
- "fxaa",
- "msaa",
- pytest.param(
- "ssaa",
- marks=pytest.mark.xfail(
- reason="SSAA broken on multiple plots",
- strict=True
+@pytest.mark.parametrize(
+ "aa",
+ [
+ False,
+ "fxaa",
+ "msaa",
+ pytest.param(
+ "ssaa",
+ marks=pytest.mark.xfail(reason="SSAA broken on multiple plots", strict=True),
),
- ),
-])
-def test_background_plotting_plots(qtbot, plotting, ensure_closed, aa):
+ ],
+)
+def test_background_plotting_plots(qtbot, plotting, ensure_closed, aa) -> None: # noqa: ARG001, C901, D103
plotter = BackgroundPlotter(
show=True,
off_screen=False,
@@ -1041,7 +1044,7 @@ def test_background_plotting_plots(qtbot, plotting, ensure_closed, aa):
)
skip_reason = None
if aa == "fxaa": # Breaks on Windows and mesa
- if platform.system()=="Windows":
+ if platform.system() == "Windows":
skip_reason = "FXAA segfaults Windows"
else:
# Check if Mesa
@@ -1053,9 +1056,8 @@ def test_background_plotting_plots(qtbot, plotting, ensure_closed, aa):
skip_reason = "FXAA broken on Mesa"
elif aa == "msaa":
pytest.importorskip("pyvista", minversion="0.37")
- elif aa == "ssaa":
- if sys.platform == "darwin":
- pytest.skip("Works sometimes on Darwin")
+ elif aa == "ssaa" and sys.platform == "darwin":
+ pytest.skip("Works sometimes on Darwin")
if skip_reason:
plotter.close()
pytest.skip(skip_reason)
@@ -1068,19 +1070,16 @@ def test_background_plotting_plots(qtbot, plotting, ensure_closed, aa):
plotter.camera.zoom(5) # fill it
if aa:
plotter.enable_anti_aliasing(aa_type=aa)
- if platform.system() != "macOS":
- ctx = qtbot.wait_exposed(plotter)
- else:
- ctx = nullcontext()
+ ctx = qtbot.wait_exposed(plotter) if platform.system() != "macOS" else nullcontext()
with ctx:
plotter.window().show()
img = np.array(plotter.image)
non_black = img.any(-1).astype(bool).mean()
del img
- # TODO: This is possibly a bug indicative of the view being wrong
+ # TODO: This is possibly a bug indicative of the view being wrong # noqa: FIX002, TD002, TD003
if sys.platform == "darwin" and platform.machine() == "arm64":
- ratio = 2.
+ ratio = 2.0
else:
- ratio = 1.
- assert 0.9 / ratio < non_black < 1. / ratio
+ ratio = 1.0
+ assert 0.9 / ratio < non_black < 1.0 / ratio
plotter.close()
diff --git a/tests/test_qt.py b/tests/test_qt.py
index abb74984..4577a011 100644
--- a/tests/test_qt.py
+++ b/tests/test_qt.py
@@ -1,8 +1,14 @@
+from __future__ import annotations # noqa: D100
+
import pytest
-def test_no_qt_binding(no_qt):
- from pyvistaqt import BackgroundPlotter, MainWindow, MultiPlotter, QtInteractor
+def test_no_qt_binding(no_qt) -> None: # noqa: ARG001, D103
+ from pyvistaqt import BackgroundPlotter
+ from pyvistaqt import MainWindow
+ from pyvistaqt import MultiPlotter
+ from pyvistaqt import QtInteractor
+
with pytest.raises(RuntimeError, match="No Qt binding"):
BackgroundPlotter()
with pytest.raises(RuntimeError, match="No Qt binding"):