diff --git a/.flake8 b/.flake8
deleted file mode 100644
index d3e28c1..0000000
--- a/.flake8
+++ /dev/null
@@ -1,21 +0,0 @@
-[flake8]
-max-line-length = 88
-extend-ignore =
- # whitespace before ':'
- E203
- # missing type annotation for self in method
- ANN101
- # handle error-cases first
- SIM106
- # fixture '{name}' does not return anything, add leading underscore
- PT004
- # pytest.raises({exception}) is too broad
- PT011
-
-per-file-ignores =
- # simplify tests by ignoring some unnecessary rules
- test/*:E501,INP001,SC200,ANN001,ANN201,ANN202,QGS105
-
-ban-relative-imports = true
-spellcheck-targets = names
-dictionaries = en_US,python,technical
diff --git a/.gitignore b/.gitignore
index 75ef666..2b65f7b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
__pycache__
.coverage
coverage.xml
+.ruff_cache
dist
build
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7efb306..d3c6c26 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -10,35 +10,27 @@ repos:
- id: check-added-large-files
- id: mixed-line-ending
args: [--fix=lf]
- - repo: https://github.com/PyCQA/isort
- rev: 5.12.0
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.0.292
hooks:
- - id: isort
+ - id: ruff
+ args: [--fix, --exit-non-zero-on-fix]
- repo: https://github.com/psf/black
- rev: 22.3.0
+ rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v0.931
+ rev: v1.4.1
hooks:
- id: mypy
- repo: https://github.com/PyCQA/flake8
- rev: 3.9.1
+ rev: 6.0.0
hooks:
- id: flake8
additional_dependencies:
- - flake8-bugbear==21.4.3
- - pep8-naming==0.11.1
- - flake8-annotations==2.6.2
+ - flake8-pyproject==1.2.3
+ - flake8-spellcheck==0.28.0
- flake8-qgis==1.0.0
- - flake8-print==4.0.0
- - flake8-tidy-imports==4.4.1
- - flake8-comprehensions==3.6.1
- - flake8-spellcheck==0.24.0
- - flake8-simplify==0.14.1
- - flake8-pytest-style==1.5.0
- - flake8-pie==0.14.0
- - flake8-no-pep420==1.1.1
- repo: https://github.com/igorshubovych/markdownlint-cli
rev: v0.32.2
hooks:
diff --git a/pyproject.toml b/pyproject.toml
index 59f2f44..71d818d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,5 +1,65 @@
-[tool.isort]
-profile = "black"
+[tool.ruff]
+ignore = [
+ "ANN101", # Missing type annotation for self in method
+ ]
+line-length = 88
+
+# List of all rules https://docs.astral.sh/ruff/rules/
+select = [
+ "ANN", # flake8-annotations
+ "B", # flake8-bugbear
+ "C", # flake8-comprehensions
+ "C90", # flake8, mccabe
+ "E", # flake8, pycodestyle
+ "F", # flake8, Pyflakes
+ "I", # isort
+ "INP", # flake8-no-pep420
+ "PIE", # flake8-pie
+ "PGH", # pygrep-hooks
+ "PL", # pylint
+ "PT", # flake8-pytest-style
+ "RUF", # Ruff-specific rules
+ "SIM", # flake8-simplify
+ "T", # flake8-print
+ "ICN", # flake8-import-conventions
+ "TCH", # flake8-type-checking
+ "TID", # flake8-tidy-imports
+ "W", # flake8, pycodestyle
+ "UP", # pyupgrade
+ ]
+
+# Avoiding flagging (and removing) `SC200` from any `# noqa`
+# directives, despite Ruff's lack of support for `flake8-spellcheck`.
+external = ["SC200"]
+
+target-version = "py39"
+
+[tool.ruff.flake8-tidy-imports]
+ban-relative-imports = "all"
+
+[tool.ruff.per-file-ignores]
+"test*" = [
+ "INP001",
+ "ANN201",
+ "ANN202",
+ "ANN401",
+ "E501",
+ "PLR2004", # Magic value used in comparison, consider replacing {value} with a constant variable
+ "PLR0913", # Too many arguments to function call (len(args) > 5)
+ ]
+
+
+[tool.flake8]
+max-line-length = 88
+spellcheck-targets = "names"
+dictionaries = "en_US,python,technical"
+extend-ignore = [
+ "E203", # whitespace before ':'
+ "E501", # line length (checked by ruff now, possible mismatches)
+]
+per-file-ignores = [
+ "test/*:INP001,SC200,QGS105",
+]
[tool.mypy]
follow_imports = "normal"
diff --git a/quality-result-gui.code-workspace b/quality-result-gui.code-workspace
index 71ec88b..a7ccb14 100644
--- a/quality-result-gui.code-workspace
+++ b/quality-result-gui.code-workspace
@@ -1,53 +1,62 @@
{
- "extensions": {
- "recommendations": [
- "editorconfig.editorconfig",
- "mikestead.dotenv",
- ]
- },
- "folders": [
- {
- "path": "."
- }
- ],
- "settings": {
- "python.languageServer": "Pylance",
- "python.testing.pytestEnabled": true,
- "python.testing.unittestEnabled": false,
- "python.linting.enabled": true,
- "python.linting.flake8Enabled": true,
- "python.linting.mypyEnabled": true,
- "python.linting.pylintEnabled": false,
- "python.formatting.provider": "black",
- "editor.formatOnSave": true,
- "[python]": {
- "editor.codeActionsOnSave": {
- "source.organizeImports": true
- }
- },
- "files.associations": {
- "*.ts": "xml"
- },
- "editor.bracketPairColorization.enabled": true,
- "editor.guides.bracketPairs": "active",
- },
- "launch": {
- "configurations": [
- {
- "name": "QGIS debugpy",
- "type": "python",
- "request": "attach",
- "connect": {
- "host": "localhost",
- "port": 5678
- },
- "pathMappings": [
- {
- "localRoot": "${workspaceFolder}",
- "remoteRoot": "${workspaceFolder}"
- }
- ]
- }
- ],
- }
+ "extensions": {
+ "recommendations": [
+ "editorconfig.editorconfig",
+ "mikestead.dotenv",
+ "ms-python.python",
+ "ms-python.mypy-type-checker",
+ "ms-python.black-formatter",
+ "ms-python.flake8",
+ "charliermarsh.ruff",
+ ]
+ },
+ "folders": [
+ {
+ "path": "."
+ }
+ ],
+ "settings": {
+ "python.languageServer": "Pylance",
+ // Tests
+ "python.testing.pytestEnabled": true,
+ // Linting
+ "flake8.importStrategy": "fromEnvironment",
+ "ruff.importStrategy": "fromEnvironment",
+ "mypy-type-checker.importStrategy": "fromEnvironment",
+ // Formatting
+ "isort.check": false,
+ "black-formatter.importStrategy": "fromEnvironment",
+ "[python]": {
+ "editor.formatOnSave": true,
+ "editor.codeActionsOnSave": {
+ "source.organizeImports.ruff": true,
+ "source.fixAll": true
+ },
+ "editor.defaultFormatter": "ms-python.black-formatter",
+ },
+ "files.associations": {
+ "*.ts": "xml"
+ },
+ "editor.bracketPairColorization.enabled": true,
+ "editor.guides.bracketPairs": "active",
+ },
+ "launch": {
+ "configurations": [
+ {
+ "name": "QGIS debugpy",
+ "type": "python",
+ "request": "attach",
+ "connect": {
+ "host": "localhost",
+ "port": 5678
+ },
+ "pathMappings": [
+ {
+ "localRoot": "${workspaceFolder}",
+ "remoteRoot": "${workspaceFolder}"
+ }
+ ]
+ }
+ ],
+ }
}
diff --git a/requirements.in b/requirements.in
index 5f97de8..9323dc7 100644
--- a/requirements.in
+++ b/requirements.in
@@ -8,33 +8,26 @@ pytest-timeout==1.4.2
pytest-order==1.0.0
pytest-dotenv==0.5.2
+#stubs
+pyqt5-stubs==5.15.6.0
+
# lock here since 1.4.1 has no binaries
atomicwrites==1.4.0
# linting
-pre-commit==3.2.2
-mypy==0.931
-isort==5.12.0
-black==22.3.0
-flake8==3.9.1
-flake8-bugbear==21.4.3
-pep8-naming==0.11.1
-flake8-annotations==2.6.2
+pre-commit==3.4.0
+mypy==1.4.1
+black==23.7.0
+ruff==0.0.292
+
+# flake8 libraries not included in ruff
+flake8==6.0.0
+flake8-pyproject==1.2.3
+flake8-spellcheck==0.28.0
flake8-qgis==1.0.0
-flake8-print==4.0.0
-flake8-tidy-imports==4.4.1
-flake8-comprehensions==3.6.1
-flake8-spellcheck==0.24.0
-flake8-simplify==0.14.1
-flake8-pytest-style==1.5.0
-flake8-pie==0.14.0
-flake8-no-pep420==1.1.1
# tools
-qgis-plugin-dev-tools==0.6.0
-
-# typing
-PyQt5-stubs==5.15.6.0
+qgis-plugin-dev-tools==0.5.0
# NOTE: Runtime requirements for QGIS plugin are defined in setup.cfg
diff --git a/requirements.txt b/requirements.txt
index 9ff51a5..3386f25 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -4,125 +4,90 @@
#
# pip-compile requirements.in
#
+
-e file:.
# via -r requirements.in
astor==0.8.1
- # via
- # flake8-qgis
- # flake8-simplify
+ # via flake8-qgis
atomicwrites==1.4.0
# via
# -r requirements.in
# pytest
-attrs==22.1.0
- # via
- # flake8-bugbear
- # pytest
-black==22.3.0
+attrs==23.1.0
+ # via pytest
+black==23.7.0
# via -r requirements.in
-certifi==2022.9.24
+certifi==2023.7.22
# via requests
-cfgv==3.3.1
+cfgv==3.4.0
# via pre-commit
-charset-normalizer==2.1.1
+charset-normalizer==3.3.0
# via requests
-click==8.1.3
+click==8.1.7
# via black
-colorama==0.4.5
+colorama==0.4.6
# via
# click
# pytest
-coverage[toml]==6.5.0
- # via pytest-cov
-distlib==0.3.6
+coverage[toml]==7.3.2
+ # via
+ # coverage
+ # pytest-cov
+distlib==0.3.7
# via virtualenv
-filelock==3.8.0
+filelock==3.12.4
# via virtualenv
-flake8==3.9.1
+flake8==6.0.0
# via
# -r requirements.in
- # flake8-annotations
- # flake8-bugbear
- # flake8-comprehensions
- # flake8-no-pep420
- # flake8-polyfill
- # flake8-print
+ # flake8-pyproject
# flake8-qgis
- # flake8-simplify
# flake8-spellcheck
- # flake8-tidy-imports
-flake8-annotations==2.6.2
- # via -r requirements.in
-flake8-bugbear==21.4.3
- # via -r requirements.in
-flake8-comprehensions==3.6.1
- # via -r requirements.in
-flake8-no-pep420==1.1.1
- # via -r requirements.in
-flake8-pie==0.14.0
- # via -r requirements.in
-flake8-plugin-utils==1.3.2
- # via flake8-pytest-style
-flake8-polyfill==1.0.2
- # via pep8-naming
-flake8-print==4.0.0
- # via -r requirements.in
-flake8-pytest-style==1.5.0
+flake8-pyproject==1.2.3
# via -r requirements.in
flake8-qgis==1.0.0
# via -r requirements.in
-flake8-simplify==0.14.1
+flake8-spellcheck==0.28.0
# via -r requirements.in
-flake8-spellcheck==0.24.0
- # via -r requirements.in
-flake8-tidy-imports==4.4.1
- # via -r requirements.in
-identify==2.5.6
+identify==2.5.30
# via pre-commit
idna==3.4
# via requests
-importlib-metadata==5.0.0
+importlib-metadata==6.8.0
# via qgis-plugin-dev-tools
-iniconfig==1.1.1
+iniconfig==2.0.0
# via pytest
-isort==5.12.0
- # via -r requirements.in
-mccabe==0.6.1
+mccabe==0.7.0
# via flake8
-mypy==0.931
+mypy==1.4.1
# via -r requirements.in
-mypy-extensions==0.4.3
+mypy-extensions==1.0.0
# via
# black
# mypy
-nodeenv==1.7.0
+nodeenv==1.8.0
# via pre-commit
-packaging==21.3
+packaging==23.2
# via
+ # black
# pytest
# qgis-plugin-dev-tools
-pathspec==0.10.1
+pathspec==0.11.2
# via black
-pep8-naming==0.11.1
- # via -r requirements.in
-platformdirs==2.5.2
+platformdirs==3.11.0
# via
# black
# virtualenv
-pluggy==1.0.0
+pluggy==1.3.0
# via pytest
-pre-commit==3.2.2
+pre-commit==3.4.0
# via -r requirements.in
py==1.11.0
# via pytest
-pycodestyle==2.7.0
- # via
- # flake8
- # flake8-print
-pyflakes==2.3.1
+pycodestyle==2.10.0
+ # via flake8
+pyflakes==3.0.1
# via flake8
-pyparsing==3.0.9
- # via packaging
pyqt5-stubs==5.15.6.0
# via -r requirements.in
pytest==6.2.5
@@ -149,38 +114,38 @@ pytest-qt==3.3.0
# via -r requirements.in
pytest-timeout==1.4.2
# via -r requirements.in
-python-dotenv==0.21.0
+python-dotenv==1.0.0
# via
# pytest-dotenv
# qgis-plugin-dev-tools
-pyyaml==6.0
+pyyaml==6.0.1
# via pre-commit
-qgis-plugin-dev-tools==0.6.0
+qgis-plugin-dev-tools==0.5.0
# via -r requirements.in
-qgis-plugin-tools==0.3.0
+qgis-plugin-tools==0.3.1
# via quality-result-gui
-requests==2.28.1
+requests==2.31.0
# via qgis-plugin-dev-tools
-six==1.16.0
- # via flake8-print
+ruff==0.0.292
+ # via -r requirements.in
toml==0.10.2
# via pytest
tomli==2.0.1
# via
# black
# coverage
+ # flake8-pyproject
# mypy
# qgis-plugin-dev-tools
-typing-extensions==4.4.0
+typing-extensions==4.8.0
# via
# black
- # flake8-pie
# mypy
-urllib3==1.26.12
+urllib3==2.0.6
# via requests
-virtualenv==20.16.5
+virtualenv==20.24.5
# via pre-commit
-zipp==3.10.0
+zipp==3.17.0
# via importlib-metadata
# The following packages are considered to be unsafe in a requirements file:
diff --git a/setup.py b/setup.py
index aba6e57..6068493 100644
--- a/setup.py
+++ b/setup.py
@@ -1,3 +1,3 @@
-from setuptools import setup # noqa: INP001
+from setuptools import setup
setup()
diff --git a/src/quality_result_gui/api/quality_api_client.py b/src/quality_result_gui/api/quality_api_client.py
index b90be7d..d21ae41 100644
--- a/src/quality_result_gui/api/quality_api_client.py
+++ b/src/quality_result_gui/api/quality_api_client.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -18,7 +18,7 @@
# along with quality-result-gui. If not, see .
from abc import ABC, abstractmethod
-from typing import List, Optional
+from typing import Optional
from qgis.core import QgsCoordinateReferenceSystem
@@ -27,7 +27,7 @@
class QualityResultClient(ABC):
@abstractmethod
- def get_results(self) -> Optional[List[QualityError]]:
+ def get_results(self) -> Optional[list[QualityError]]:
"""
Retrieve latest quality errors from API
diff --git a/src/quality_result_gui/api/types/quality_error.py b/src/quality_result_gui/api/types/quality_error.py
index 3e3bc8e..a1a016d 100644
--- a/src/quality_result_gui/api/types/quality_error.py
+++ b/src/quality_result_gui/api/types/quality_error.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -95,5 +95,5 @@ class QualityError:
geometry: QgsGeometry
is_user_processed: bool
- def __getitem__(self, item: str) -> Any:
+ def __getitem__(self, item: str) -> Any: # noqa: ANN401
return getattr(self, item)
diff --git a/src/quality_result_gui/layer_mapping.py b/src/quality_result_gui/layer_mapping.py
index ef79fff..b9a698c 100644
--- a/src/quality_result_gui/layer_mapping.py
+++ b/src/quality_result_gui/layer_mapping.py
@@ -18,14 +18,14 @@
# along with quality-result-gui. If not, see .
from dataclasses import dataclass
-from typing import Dict, Optional
+from typing import Optional
from qgis.core import QgsField, QgsProject, QgsVectorLayer
@dataclass
class LayerMapping:
- layer_map: Optional[Dict[str, str]]
+ layer_map: Optional[dict[str, str]]
def get_layer_alias(self, feature_type: str) -> str:
layer = self._get_layer(feature_type)
diff --git a/src/quality_result_gui/quality_data_fetcher.py b/src/quality_result_gui/quality_data_fetcher.py
index 20fddc9..c75c09c 100644
--- a/src/quality_result_gui/quality_data_fetcher.py
+++ b/src/quality_result_gui/quality_data_fetcher.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -19,7 +19,7 @@
import logging
from enum import Enum, auto
-from typing import TYPE_CHECKING, List, Optional
+from typing import TYPE_CHECKING, Optional
from qgis.PyQt.QtCore import QObject, QThread, QTimer, pyqtSignal, pyqtSlot
from qgis_plugin_tools.tools.i18n import tr
@@ -112,7 +112,7 @@ def _check_api(self) -> None:
except (QualityResultClientError, QualityResultServerError) as e:
LOGGER.warning(
- f"failed to check quality results api: {str(e)}", stack_info=True
+ f"failed to check quality results api: {e!s}", stack_info=True
)
self.status_changed.emit(CheckStatus.RESULT_FAILED)
@@ -145,7 +145,7 @@ def _worker_status_changed(self, status: CheckStatus) -> None:
self.status_changed.emit(status)
@pyqtSlot(list)
- def _worker_results_received(self, results: List["QualityError"]) -> None:
+ def _worker_results_received(self, results: list["QualityError"]) -> None:
self.results_received.emit(results)
@pyqtSlot()
diff --git a/src/quality_result_gui/quality_error_manager.py b/src/quality_result_gui/quality_error_manager.py
index 0edcf04..07717fb 100644
--- a/src/quality_result_gui/quality_error_manager.py
+++ b/src/quality_result_gui/quality_error_manager.py
@@ -18,7 +18,7 @@
# along with quality-result-gui. If not, see .
-from typing import TYPE_CHECKING, Dict, Optional, cast
+from typing import TYPE_CHECKING, Optional, cast
from qgis.gui import QgisInterface
from qgis.PyQt.QtCore import QObject, pyqtSignal
@@ -183,7 +183,7 @@ def add_filter(self, filter: AbstractQualityErrorFilter) -> None:
self.dock_widget.filter_menu.add_filter_menu(filter.menu)
self._filter_model.add_filter(filter)
- def set_layer_mapping(self, layer_mapping: Dict[str, str]) -> None:
+ def set_layer_mapping(self, layer_mapping: dict[str, str]) -> None:
QualityResultManagerSettings.get().set_layer_mapping(
LayerMapping(layer_map=layer_mapping)
)
diff --git a/src/quality_result_gui/quality_error_visualizer.py b/src/quality_result_gui/quality_error_visualizer.py
index 11d21ce..9bee9ca 100644
--- a/src/quality_result_gui/quality_error_visualizer.py
+++ b/src/quality_result_gui/quality_error_visualizer.py
@@ -19,20 +19,23 @@
import json
import logging
+from collections.abc import Iterable
from pathlib import Path
-from typing import Iterable, List, Optional, cast
+from typing import TYPE_CHECKING, Optional, cast
from qgis.core import QgsAnnotationLayer, QgsCoordinateReferenceSystem, QgsProject
from qgis.gui import QgisInterface
from qgis.utils import iface as utils_iface
from quality_result_gui.api.types.quality_error import QualityError
-from quality_result_gui.configuration import QualityLayerStyleConfig
from quality_result_gui.env import IS_DEVELOPMENT_MODE, TEST_JSON_FILE_PATH
from quality_result_gui.quality_layer import QualityErrorLayer
from quality_result_gui.ui.quality_error_tree_view import SelectionType
from quality_result_gui.utils import layer_utils
+if TYPE_CHECKING:
+ from quality_result_gui.configuration import QualityLayerStyleConfig
+
iface = cast(QgisInterface, utils_iface)
LOGGER = logging.getLogger(__name__)
@@ -143,7 +146,7 @@ def remove_quality_error_layer(self) -> None:
QgsProject.instance().removeMapLayer(layer.id())
def zoom_to_geometries_and_flash(
- self, quality_errors: List[QualityError], preserve_scale: bool = False
+ self, quality_errors: list[QualityError], preserve_scale: bool = False
) -> None:
if len(quality_errors) > 0:
layer_utils.zoom_to_geometries_and_flash(
diff --git a/src/quality_result_gui/quality_errors_filters.py b/src/quality_result_gui/quality_errors_filters.py
index 3513d57..f09529e 100644
--- a/src/quality_result_gui/quality_errors_filters.py
+++ b/src/quality_result_gui/quality_errors_filters.py
@@ -25,11 +25,7 @@
TYPE_CHECKING,
Any,
Callable,
- Dict,
- Hashable,
- List,
Optional,
- Set,
cast,
)
@@ -45,6 +41,8 @@
from quality_result_gui.quality_errors_tree_model import QualityErrorTreeItemType
if TYPE_CHECKING:
+ from collections.abc import Hashable
+
from qgis.PyQt.QtWidgets import QWidget
@@ -58,9 +56,9 @@ def __init__(self, title: str, parent: Optional["QWidget"] = None) -> None:
self._select_all_section_enabled = False
self._sorted = False
- self._filter_actions: List[QAction] = []
+ self._filter_actions: list[QAction] = []
- def mouseReleaseEvent(self, e: QMouseEvent) -> None: # noqa: N802 (qt override)
+ def mouseReleaseEvent(self, e: QMouseEvent) -> None: # (qt override)
if not self.activeAction() or not self.activeAction().isEnabled():
super().mouseReleaseEvent(e)
else:
@@ -123,7 +121,7 @@ def _add_select_all_section(self) -> None:
existing_actions = self.actions()
first_action = existing_actions[0] if existing_actions else None
- separator = self.insertSeparator(first_action) # type: ignore
+ separator = self.insertSeparator(first_action)
self.insertAction(separator, deselect_all_action)
self.insertAction(deselect_all_action, select_all_action)
@@ -229,13 +227,15 @@ def __init__(self, title: str, parent: Optional[QObject] = None) -> None:
"""
super().__init__(parent=parent)
- self._accepted_values: Set[Any] = set()
- self._filter_value_action_map: Dict[Hashable, QAction] = {}
+ self._accepted_values: set[Any] = set()
+ self._filter_value_action_map: dict[Hashable, QAction] = {}
self.menu = FilterMenu(title)
@abstractmethod
- def accept_row(self, item_type: QualityErrorTreeItemType, item_value: Any) -> bool:
+ def accept_row(
+ self, item_type: QualityErrorTreeItemType, item_value: Any # noqa: ANN401
+ ) -> bool:
"""The actual filter function that inherited classes should be implemented.
Args:
@@ -250,7 +250,7 @@ def accept_row(self, item_type: QualityErrorTreeItemType, item_value: Any) -> bo
"""
raise NotImplementedError()
- def update_filter_from_errors(self, quality_errors: List["QualityError"]) -> None:
+ def update_filter_from_errors(self, quality_errors: list["QualityError"]) -> None:
"""Updates filters dynamically from a given list of quality errors.
Should be implemented in inherited classes if feature is wanted.
@@ -264,7 +264,7 @@ def update_filter_from_errors(self, quality_errors: List["QualityError"]) -> Non
"""
raise NotImplementedError()
- def _sync_filtered(self, value: Any, checked: bool) -> None:
+ def _sync_filtered(self, value: Any, checked: bool) -> None: # noqa: ANN401
"""Syncs accepted filter values
Should be connected to checkable action's toggle signal with functool.partial
@@ -282,7 +282,7 @@ def _sync_filtered(self, value: Any, checked: bool) -> None:
self.filters_changed.emit()
- def _refresh_filters(self, new_filters: Dict[Any, str]) -> None:
+ def _refresh_filters(self, new_filters: dict[Any, str]) -> None:
"""Adds filters not yet present and removes filters not present anymore.
Args:
@@ -327,7 +327,9 @@ def _refresh_error_type_filters(
filter_label = new_filters[filter_value]()
self._add_filter_item(filter_value, filter_label)
- def _add_filter_item(self, filter_value: Any, filter_label: str) -> None:
+ def _add_filter_item(
+ self, filter_value: Any, filter_label: str # noqa: ANN401
+ ) -> None:
"""Adds a filter item to the filter
Args:
@@ -343,7 +345,7 @@ def _add_filter_item(self, filter_value: Any, filter_label: str) -> None:
self.filters_changed.emit()
- def _remove_filter_item(self, filter_value: Any) -> None:
+ def _remove_filter_item(self, filter_value: Any) -> None: # noqa: ANN401
"""Removes the filter item
Args:
@@ -366,7 +368,7 @@ class ErrorTypeFilter(AbstractQualityErrorFilter):
This is a static filter that shows always all the defined error types.
"""
- _accepted_values: Set[QualityErrorTreeItemType]
+ _accepted_values: set[QualityErrorTreeItemType]
def __init__(self) -> None:
super().__init__(self.get_error_type_filter_menu_label())
@@ -379,7 +381,9 @@ def __init__(self) -> None:
def get_error_type_filter_menu_label() -> str:
return tr("Error type")
- def accept_row(self, item_type: QualityErrorTreeItemType, item_value: Any) -> bool:
+ def accept_row(
+ self, item_type: QualityErrorTreeItemType, item_value: Any # noqa: ANN401
+ ) -> bool:
if item_type == QualityErrorTreeItemType.ERROR:
return cast(QualityError, item_value).error_type in self._accepted_values
@@ -394,7 +398,7 @@ class FeatureTypeFilter(AbstractQualityErrorFilter):
received errors.
"""
- _accepted_values: Set[str]
+ _accepted_values: set[str]
def __init__(self) -> None:
super().__init__(self.get_feature_type_filter_menu_label())
@@ -405,13 +409,15 @@ def __init__(self) -> None:
def get_feature_type_filter_menu_label() -> str:
return tr("Feature type")
- def accept_row(self, item_type: QualityErrorTreeItemType, item_value: Any) -> bool:
+ def accept_row(
+ self, item_type: QualityErrorTreeItemType, item_value: Any # noqa: ANN401
+ ) -> bool:
if item_type == QualityErrorTreeItemType.FEATURE_TYPE:
return cast(str, item_value) in self._accepted_values
return True
- def update_filter_from_errors(self, quality_errors: List["QualityError"]) -> None:
+ def update_filter_from_errors(self, quality_errors: list["QualityError"]) -> None:
"""
Args:
@@ -438,7 +444,7 @@ class AttributeFilter(AbstractQualityErrorFilter):
received errors.
"""
- _accepted_values: Set[str]
+ _accepted_values: set[str]
def __init__(self) -> None:
super().__init__(self.get_attribute_name_filter_menu_label())
@@ -449,7 +455,9 @@ def __init__(self) -> None:
def get_attribute_name_filter_menu_label() -> str:
return tr("Attribute Filter")
- def accept_row(self, item_type: QualityErrorTreeItemType, item_value: Any) -> bool:
+ def accept_row(
+ self, item_type: QualityErrorTreeItemType, item_value: Any # noqa: ANN401
+ ) -> bool:
if item_type == QualityErrorTreeItemType.ERROR:
attribute_name = cast(QualityError, item_value).attribute_name
if attribute_name:
@@ -457,7 +465,7 @@ def accept_row(self, item_type: QualityErrorTreeItemType, item_value: Any) -> bo
return True
- def update_filter_from_errors(self, quality_errors: List["QualityError"]) -> None:
+ def update_filter_from_errors(self, quality_errors: list["QualityError"]) -> None:
attribute_names_in_errors = { # Dict[filter_value, filter_label]
error.attribute_name: self._get_label_value(
error.feature_type, error.attribute_name
diff --git a/src/quality_result_gui/quality_errors_tree_model.py b/src/quality_result_gui/quality_errors_tree_model.py
index 8ca98d0..925efb2 100644
--- a/src/quality_result_gui/quality_errors_tree_model.py
+++ b/src/quality_result_gui/quality_errors_tree_model.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -21,17 +21,12 @@
import enum
import logging
from abc import abstractmethod
+from collections.abc import Iterable, Iterator
from typing import (
TYPE_CHECKING,
Any,
- Dict,
- Iterable,
- Iterator,
- List,
NewType,
Optional,
- Set,
- Tuple,
Union,
cast,
overload,
@@ -92,14 +87,14 @@ def get_error_description_label() -> str:
def get_error_feature_types(
- quality_results: List[QualityError],
-) -> Set[str]:
+ quality_results: list[QualityError],
+) -> set[str]:
return {errors.feature_type for errors in quality_results}
def get_error_feature_attributes(
- quality_errors: List[QualityError],
-) -> Set[str]:
+ quality_errors: list[QualityError],
+) -> set[str]:
return {error.attribute_name for error in quality_errors if error.attribute_name}
@@ -157,14 +152,14 @@ class QualityErrorTreeItemType(enum.Enum):
ErrorDataType = NewType(
"ErrorDataType",
- Tuple[QualityErrorTreeItemType, Any],
+ tuple[QualityErrorTreeItemType, Any],
)
class QualityErrorTreeItem:
def __init__(
self,
- data: List[Any],
+ data: list[Any],
key: str,
item_type: QualityErrorTreeItemType,
parent: Optional["QualityErrorTreeItem"] = None,
@@ -172,8 +167,8 @@ def __init__(
self.key = key
self._item_parent = parent
self._item_data = data
- self._child_items: List["QualityErrorTreeItem"] = []
- self._child_item_map: Dict[str, int] = {}
+ self._child_items: list["QualityErrorTreeItem"] = []
+ self._child_item_map: dict[str, int] = {}
self.item_type = item_type
@@ -204,7 +199,7 @@ def row(self) -> int:
def column_count(self) -> int:
return len(self._item_data)
- def data(
+ def data( # noqa: C901, PLR0911, PLR0912
self, column_index: int, role: Qt.ItemDataRole = Qt.DisplayRole
) -> QVariant:
if not (column_index >= 0 and column_index < len(self._item_data)):
@@ -351,7 +346,7 @@ def parent(
return self.createIndex(parent_item.row(), 0, parent_item)
- def rowCount(self, parent: QModelIndex) -> int: # noqa: N802 (qt override)
+ def rowCount(self, parent: QModelIndex) -> int: # (qt override)
if parent.column() > 0:
return 0
@@ -362,7 +357,7 @@ def rowCount(self, parent: QModelIndex) -> int: # noqa: N802 (qt override)
return parent_item.child_count()
- def columnCount(self, parent: QModelIndex) -> int: # noqa: N802 (qt override)
+ def columnCount(self, parent: QModelIndex) -> int: # (qt override)
if not parent.isValid():
parent_item = self._root_item
else:
@@ -380,7 +375,7 @@ def data(
return item.data(index.column(), role)
- def headerData( # noqa: N802 (qt override)
+ def headerData( # (qt override)
self,
section: int,
orientation: Qt.Orientation,
@@ -400,8 +395,11 @@ def headerData( # noqa: N802 (qt override)
return QVariant()
return QVariant()
- def setData( # noqa: N802 (qt override)
- self, index: QModelIndex, value: Any, role: Qt.ItemDataRole = Qt.EditRole
+ def setData( # (qt override)
+ self,
+ index: QModelIndex,
+ value: Any, # noqa: ANN401
+ role: Qt.ItemDataRole = Qt.EditRole,
) -> bool:
if not index.isValid() or role == Qt.EditRole:
return False
@@ -448,7 +446,7 @@ def flags( # (qt override)
return super().flags(index)
- def refresh_model(self, quality_errors: List[QualityError]) -> None:
+ def refresh_model(self, quality_errors: list[QualityError]) -> None:
updated_quality_error_ids = {
error.unique_identifier for error in quality_errors
}
@@ -476,7 +474,7 @@ def refresh_model(self, quality_errors: List[QualityError]) -> None:
if error.unique_identifier in new_error_ids
)
- errors_to_be_deleted: List[Tuple[QualityErrorTreeItem, QModelIndex]] = []
+ errors_to_be_deleted: list[tuple[QualityErrorTreeItem, QModelIndex]] = []
for i in range(self.rowCount(QModelIndex())):
for index in _get_quality_errors_indexes(
@@ -493,7 +491,7 @@ def refresh_model(self, quality_errors: List[QualityError]) -> None:
def _update_model_data(
self,
errors_to_be_added: Iterable[QualityError],
- errors_to_be_deleted: List[Tuple[QualityErrorTreeItem, QModelIndex]],
+ errors_to_be_deleted: list[tuple[QualityErrorTreeItem, QModelIndex]],
) -> None:
"""
Updates model data based on new and deleted quality errors.
@@ -663,7 +661,7 @@ def __init__(self, parent: Optional[QObject] = None) -> None:
super().__init__(parent)
self.setFilterRole(Qt.UserRole)
- def filterAcceptsRow( # noqa: N802 (qt override)
+ def filterAcceptsRow( # (qt override)
self, source_row: int, source_parent: QModelIndex
) -> bool:
source_index = self.sourceModel().index(source_row, 0, source_parent)
@@ -689,7 +687,9 @@ def filterAcceptsRow( # noqa: N802 (qt override)
@abstractmethod
def accept_row(
- self, tree_item_type: QualityErrorTreeItemType, tree_item_value: Any
+ self,
+ tree_item_type: QualityErrorTreeItemType,
+ tree_item_value: Any, # noqa: ANN401
) -> bool:
raise NotImplementedError()
@@ -705,7 +705,7 @@ class FilterProxyModel(AbstractFilterProxyModel):
def __init__(self, parent: Optional[QObject] = None) -> None:
super().__init__(parent)
- self._filters: List["AbstractQualityErrorFilter"] = []
+ self._filters: list["AbstractQualityErrorFilter"] = []
def add_filter(self, filter: "AbstractQualityErrorFilter") -> None:
filter.filters_changed.connect(self.invalidateFilter)
@@ -713,7 +713,9 @@ def add_filter(self, filter: "AbstractQualityErrorFilter") -> None:
self.invalidateFilter()
- def accept_row(self, item_type: QualityErrorTreeItemType, item_value: Any) -> bool:
+ def accept_row(
+ self, item_type: QualityErrorTreeItemType, item_value: Any # noqa: ANN401
+ ) -> bool:
# TODO: Check only the changed filters.
# Now this checks all the filters when one changes
return all(
@@ -721,7 +723,7 @@ def accept_row(self, item_type: QualityErrorTreeItemType, item_value: Any) -> bo
for quality_filter in self._filters
)
- def headerData( # noqa: N802 (qt override)
+ def headerData( # (qt override)
self,
section: int,
orientation: Qt.Orientation,
@@ -774,7 +776,9 @@ def set_enabled(self, enabled: bool) -> None:
self.set_extent(None)
def accept_row(
- self, tree_item_type: QualityErrorTreeItemType, tree_item_value: Any
+ self,
+ tree_item_type: QualityErrorTreeItemType,
+ tree_item_value: Any, # noqa: ANN401
) -> bool:
if not self._extent:
return True
@@ -785,7 +789,7 @@ def accept_row(
return quality_error.geometry.intersects(self._extent)
- def headerData( # noqa: N802 (qt override)
+ def headerData( # (qt override)
self,
section: int,
orientation: Qt.Orientation,
@@ -825,7 +829,9 @@ def set_show_processed_errors(self, show_processed_errors: bool) -> None:
self.invalidateFilter()
def accept_row(
- self, tree_item_type: QualityErrorTreeItemType, tree_item_value: Any
+ self,
+ tree_item_type: QualityErrorTreeItemType,
+ tree_item_value: Any, # noqa: ANN401
) -> bool:
return not (
self._show_processed_errors is False
@@ -833,7 +839,7 @@ def accept_row(
and cast(QualityError, tree_item_value).is_user_processed is True
)
- def headerData( # noqa: N802 (qt override)
+ def headerData( # (qt override)
self,
section: int,
orientation: Qt.Orientation,
diff --git a/src/quality_result_gui/quality_layer.py b/src/quality_result_gui/quality_layer.py
index 84255f7..7854e90 100644
--- a/src/quality_result_gui/quality_layer.py
+++ b/src/quality_result_gui/quality_layer.py
@@ -18,7 +18,8 @@
# along with quality-result-gui. If not, see .
import logging
-from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Union
+from collections.abc import Iterable
+from typing import TYPE_CHECKING, Optional, Union
from qgis.core import (
QgsAnnotationLayer,
@@ -59,7 +60,7 @@ class QualityErrorLayer:
LAYER_ID_PROPERTY = "quality-result-gui-layer"
def __init__(self) -> None:
- self._annotation_ids: Dict[str, List[str]] = {}
+ self._annotation_ids: dict[str, list[str]] = {}
self.style: "QualityLayerStyleConfig" = DefaultStyleConfig()
@property
@@ -165,14 +166,14 @@ def remove_annotations(
# Consume exception, feature is not found
pass
- def _create_annotations(
+ def _create_annotations( # noqa: C901, PLR0912
self,
quality_error: "QualityError",
use_highlighted_style: bool,
- ) -> List[
+ ) -> list[
Union[QgsAnnotationMarkerItem, QgsAnnotationPolygonItem, QgsAnnotationLineItem]
]:
- annotations: List[
+ annotations: list[
Union[
QgsAnnotationMarkerItem, QgsAnnotationPolygonItem, QgsAnnotationLineItem
]
diff --git a/src/quality_result_gui/style/default_style.py b/src/quality_result_gui/style/default_style.py
index 005acc4..ffbd9fa 100644
--- a/src/quality_result_gui/style/default_style.py
+++ b/src/quality_result_gui/style/default_style.py
@@ -19,7 +19,7 @@
from dataclasses import dataclass
from importlib.resources import as_file, files
-from typing import TYPE_CHECKING, List, Optional, Union
+from typing import TYPE_CHECKING, Optional, Union
from qgis.core import (
QgsCentroidFillSymbolLayer,
@@ -131,7 +131,6 @@ def __init__(
self,
quality_error: "QualityError",
) -> None:
-
self.style: QualityLayerStyle = QualityLayerStyle(
COLORS_FOR_ERRORS,
line_width=1.2,
@@ -299,7 +298,7 @@ def _get_point_symbol(self, highlighted: bool) -> QgsMarkerSymbol:
def _set_enabled_expression(
self,
priority_symbol_layer: QgsSymbolLayer,
- geometry_layers: List[QgsSymbolLayer],
+ geometry_layers: list[QgsSymbolLayer],
) -> None:
if (
self.icon_symbol_enabled_expression is not None
@@ -318,7 +317,6 @@ def _set_enabled_expression(
def _create_priority_symbol_layer(
self, priority: QualityErrorPriority
) -> QgsSvgMarkerSymbolLayer:
-
file_path = files(resources).joinpath("icons")
if priority == QualityErrorPriority.FATAL:
@@ -328,9 +326,9 @@ def _create_priority_symbol_layer(
elif priority == QualityErrorPriority.INFO:
file_path = file_path.joinpath("quality_error_info.svg")
else:
- raise ValueError(f"Unknown priority {str(priority)}")
+ raise ValueError(f"Unknown priority {priority!s}")
- style = dict({})
+ style = {}
with as_file(file_path) as svg_file:
style["name"] = str(svg_file)
diff --git a/src/quality_result_gui/ui/quality_error_tree_view.py b/src/quality_result_gui/ui/quality_error_tree_view.py
index 7c843cc..324480c 100644
--- a/src/quality_result_gui/ui/quality_error_tree_view.py
+++ b/src/quality_result_gui/ui/quality_error_tree_view.py
@@ -17,8 +17,9 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
+from collections.abc import Generator
from types import GeneratorType
-from typing import TYPE_CHECKING, Generator, List, Optional, cast
+from typing import TYPE_CHECKING, Optional, cast
from qgis.PyQt.QtCore import QAbstractItemModel, QModelIndex, Qt, QVariant, pyqtSignal
from qgis.PyQt.QtWidgets import QTreeView, QWidget
@@ -70,7 +71,7 @@ def __init__(
self.setStyleSheet(TREE_VIEW_STYLE)
- def setModel( # noqa: N802 (override qt method)
+ def setModel( # (override qt method)
self, model: Optional[QAbstractItemModel]
) -> None:
super().setModel(model)
@@ -82,9 +83,7 @@ def setModel( # noqa: N802 (override qt method)
model.rowsInserted.connect(self._on_model_rows_inserted)
model.rowsAboutToBeRemoved.connect(self._on_rows_about_to_be_removed)
- def mousePressEvent( # noqa: N802 (override qt method)
- self, event: "QMouseEvent"
- ) -> None:
+ def mousePressEvent(self, event: "QMouseEvent") -> None: # (override qt method)
if event.button() == Qt.MouseButton.LeftButton:
self.current_selection_type = SelectionType.LeftClick
elif event.button() == Qt.MouseButton.RightButton:
@@ -95,9 +94,7 @@ def mousePressEvent( # noqa: N802 (override qt method)
self.current_selection_type = SelectionType.Other
- def keyPressEvent( # noqa: N802 (override qt method)
- self, event: "QKeyEvent"
- ) -> None:
+ def keyPressEvent(self, event: "QKeyEvent") -> None: # (override qt method)
self.current_selection_type = SelectionType.Keyboard
# Calling super will trigger currentChanged if arrow keys used
@@ -105,7 +102,7 @@ def keyPressEvent( # noqa: N802 (override qt method)
self.current_selection_type = SelectionType.Other
- def get_all_quality_errors(self) -> List[QualityError]:
+ def get_all_quality_errors(self) -> list[QualityError]:
return [
error
for i in range(self.model().rowCount())
diff --git a/src/quality_result_gui/ui/quality_errors_dock.py b/src/quality_result_gui/ui/quality_errors_dock.py
index 1123af5..ab8224c 100644
--- a/src/quality_result_gui/ui/quality_errors_dock.py
+++ b/src/quality_result_gui/ui/quality_errors_dock.py
@@ -18,7 +18,7 @@
# along with quality-result-gui. If not, see .
import logging
-from typing import TYPE_CHECKING, Optional, Type
+from typing import TYPE_CHECKING, Optional
from qgis.core import QgsApplication
from qgis.gui import QgsGui
@@ -46,10 +46,10 @@
LOGGER = logging.getLogger(__name__)
-DockWidgetUi: Type[QDockWidget] = load_ui_file(__package__, "quality_errors_dock.ui")
+DockWidgetUi: type[QDockWidget] = load_ui_file(__package__, "quality_errors_dock.ui")
-class QualityErrorsDockWidget(DockWidgetUi): # type: ignore
+class QualityErrorsDockWidget(DockWidgetUi): # type: ignore[valid-type]
"""
Graphical user interface for quality errors dock widget.
"""
@@ -102,7 +102,7 @@ def show(self) -> None:
self._register_shortcut()
return super().show()
- def closeEvent(self, event: QCloseEvent) -> None: # noqa: N802 (qt override)
+ def closeEvent(self, event: QCloseEvent) -> None: # (qt override)
QgsGui.shortcutsManager().unregisterShortcut(self.shortcut_for_toggle_errors)
self.closed.emit()
diff --git a/src/quality_result_gui/utils/layer_utils.py b/src/quality_result_gui/utils/layer_utils.py
index f286206..9879309 100644
--- a/src/quality_result_gui/utils/layer_utils.py
+++ b/src/quality_result_gui/utils/layer_utils.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import List, Optional
+from typing import Optional
from qgis.core import (
QgsCoordinateReferenceSystem,
@@ -46,7 +46,7 @@ def set_visibility_checked(layer: QgsVectorLayer, checked: bool) -> None:
def zoom_to_geometries_and_flash(
- geometries: List[QgsGeometry],
+ geometries: list[QgsGeometry],
crs: QgsCoordinateReferenceSystem,
preserve_scale: bool = False,
min_extent_height: Optional[int] = None,
@@ -75,7 +75,7 @@ def zoom_to_geometries_and_flash(
iface.mapCanvas().redrawAllLayers()
-def get_extent_from_geometries(geometries: List[QgsGeometry]) -> Optional[QgsRectangle]:
+def get_extent_from_geometries(geometries: list[QgsGeometry]) -> Optional[QgsRectangle]:
if len(geometries) == 0:
return None
diff --git a/src/quality_result_gui/utils/styling_utils.py b/src/quality_result_gui/utils/styling_utils.py
index 9435324..ee30cfa 100644
--- a/src/quality_result_gui/utils/styling_utils.py
+++ b/src/quality_result_gui/utils/styling_utils.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Dict, Tuple, Union
+from typing import Union
from qgis.core import (
QgsDrawSourceEffect,
@@ -31,7 +31,7 @@
def set_symbol_layer_data_defined_property_expressions(
- symbol_layer: QgsSymbolLayer, data_defined_property_expressions: Dict[str, str]
+ symbol_layer: QgsSymbolLayer, data_defined_property_expressions: dict[str, str]
) -> None:
"""
Sets the symbol layer data defined properties with expressions.
@@ -58,8 +58,8 @@ def set_symbol_layer_data_defined_property_expressions(
def set_symbol_layer_simple_outer_glow_effect(
symbol_layer: QgsSymbolLayer,
color_rgba: str,
- spread: Tuple[float, str] = (2.0, "MM"),
- blur: Tuple[float, str] = (2.0, "MM"),
+ spread: tuple[float, str] = (2.0, "MM"),
+ blur: tuple[float, str] = (2.0, "MM"),
opacity: float = 1,
) -> None:
"""
@@ -89,7 +89,7 @@ def set_symbol_layer_simple_outer_glow_effect(
def get_color(
- hex_or_rgb: Union[str, Tuple[int, int, int]], opacity: int = 100
+ hex_or_rgb: Union[str, tuple[int, int, int]], opacity: int = 100
) -> QColor:
color = QColor(hex_or_rgb)
color.setAlpha(int(opacity / 100 * 255))
diff --git a/src/quality_result_gui_plugin/__init__.py b/src/quality_result_gui_plugin/__init__.py
index 272d9c2..306a39c 100644
--- a/src/quality_result_gui_plugin/__init__.py
+++ b/src/quality_result_gui_plugin/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -22,8 +22,7 @@
from quality_result_gui_plugin.plugin import QualityResultGuiPlugin
-def classFactory( # noqa: N802 (qgis naming)
+def classFactory( # (qgis naming)
iface: QgisInterface,
) -> "QualityResultGuiPlugin":
-
return QualityResultGuiPlugin()
diff --git a/src/quality_result_gui_plugin/dev_tools/dev_tools_dialog.py b/src/quality_result_gui_plugin/dev_tools/dev_tools_dialog.py
index 262a348..80a56a1 100644
--- a/src/quality_result_gui_plugin/dev_tools/dev_tools_dialog.py
+++ b/src/quality_result_gui_plugin/dev_tools/dev_tools_dialog.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -35,7 +35,6 @@
class DevToolsDialog(QDialog, FORM_CLASS):
-
quality_errors_data_file_widget: QgsFileWidget
btn_open_quality_errors_dialog: QPushButton
diff --git a/src/quality_result_gui_plugin/dev_tools/mock_api_client.py b/src/quality_result_gui_plugin/dev_tools/mock_api_client.py
index eb92756..964951b 100644
--- a/src/quality_result_gui_plugin/dev_tools/mock_api_client.py
+++ b/src/quality_result_gui_plugin/dev_tools/mock_api_client.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -20,12 +20,12 @@
import json
from dataclasses import dataclass
from pathlib import Path
-from typing import List, Optional
+from typing import Optional
from qgis.core import QgsCoordinateReferenceSystem
-
from quality_result_gui.api.quality_api_client import QualityResultClient
from quality_result_gui.api.types.quality_error import QualityError
+
from quality_result_gui_plugin.dev_tools.response_parser import QualityErrorResponse
@@ -33,7 +33,7 @@
class MockQualityResultClient(QualityResultClient):
json_file_path: Path
- def get_results(self) -> Optional[List[QualityError]]:
+ def get_results(self) -> Optional[list[QualityError]]:
"""
Retrieve latest quality errors from API
diff --git a/src/quality_result_gui_plugin/dev_tools/response_parser.py b/src/quality_result_gui_plugin/dev_tools/response_parser.py
index bd55562..3e32cb2 100644
--- a/src/quality_result_gui_plugin/dev_tools/response_parser.py
+++ b/src/quality_result_gui_plugin/dev_tools/response_parser.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -18,10 +18,9 @@
# along with quality-result-gui. If not, see .
from dataclasses import dataclass, field
-from typing import Any, Dict, List
+from typing import Any
from qgis.core import QgsGeometry
-
from quality_result_gui.api.types.quality_error import (
QualityError,
QualityErrorPriority,
@@ -31,8 +30,8 @@
@dataclass
class QualityErrorResponse:
- quality_results: List[QualityError] = field(init=False)
- _errors_obj: List[Dict[str, Any]]
+ quality_results: list[QualityError] = field(init=False)
+ _errors_obj: list[dict[str, Any]]
def __post_init__(self) -> None:
self.quality_results = [
diff --git a/src/quality_result_gui_plugin/plugin.py b/src/quality_result_gui_plugin/plugin.py
index aa8fc66..ca919ea 100644
--- a/src/quality_result_gui_plugin/plugin.py
+++ b/src/quality_result_gui_plugin/plugin.py
@@ -22,6 +22,7 @@
from typing import Optional, cast
import qgis_plugin_tools
+import quality_result_gui
from qgis.core import QgsApplication, QgsProject
from qgis.gui import QgisInterface
from qgis.PyQt.QtCore import QCoreApplication, Qt, QTranslator
@@ -31,11 +32,10 @@
from qgis_plugin_tools.tools.custom_logging import setup_loggers
from qgis_plugin_tools.tools.i18n import setup_translation, tr
from qgis_plugin_tools.tools.resources import resources_path
-
-import quality_result_gui
-import quality_result_gui_plugin
from quality_result_gui.env import IS_DEVELOPMENT_MODE, TEST_JSON_FILE_PATH
from quality_result_gui.quality_error_manager import QualityResultManager
+
+import quality_result_gui_plugin
from quality_result_gui_plugin.dev_tools.dev_tools_dialog import DevToolsDialog
from quality_result_gui_plugin.dev_tools.mock_api_client import MockQualityResultClient
@@ -64,7 +64,7 @@ def __init__(self) -> None:
self.dev_tool_action: Optional[QAction] = None
self._test_json_file_path = ""
- def initGui(self) -> None: # noqa: N802 (qgis naming)
+ def initGui(self) -> None: # (qgis naming)
self._teardown_loggers = setup_loggers(
quality_result_gui.__name__,
quality_result_gui_plugin.__name__,
diff --git a/test/conftest.py b/test/conftest.py
index 0616a07..997e59f 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -17,14 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Any, Callable, List, Optional
+from typing import Any, Callable, Optional
import pytest
from pytest_mock import MockerFixture
from qgis.core import QgsCoordinateReferenceSystem, QgsGeometry
from qgis.PyQt.QtWidgets import QAction, QMenu
from qgis_plugin_tools.tools.messages import MsgBar
-
from quality_result_gui.api.quality_api_client import QualityResultClient
from quality_result_gui.api.types.quality_error import (
QualityError,
@@ -34,7 +33,7 @@
class MockQualityResultClient(QualityResultClient):
- def get_results(self) -> Optional[List[QualityError]]:
+ def get_results(self) -> Optional[list[QualityError]]:
return []
def get_crs(self) -> QgsCoordinateReferenceSystem:
@@ -47,7 +46,7 @@ def mock_api_client() -> QualityResultClient:
@pytest.fixture()
-def bypass_log_if_fails(mocker: MockerFixture) -> None:
+def _bypass_log_if_fails(mocker: MockerFixture) -> None:
"""Throws unhandled exception even though it is caught with log_if_fails"""
def mock_msg_bar(*args: Any, **kwargs: Any):
@@ -64,7 +63,7 @@ def mock_msg_bar(*args: Any, **kwargs: Any):
@pytest.fixture()
-def quality_errors() -> List[QualityError]:
+def quality_errors() -> list[QualityError]:
return [
QualityError(
QualityErrorPriority.FATAL,
@@ -152,7 +151,7 @@ def error_feature_attributes() -> list[str]:
@pytest.fixture()
-def single_quality_error() -> List[QualityError]:
+def single_quality_error() -> list[QualityError]:
return [
QualityError(
QualityErrorPriority.FATAL,
@@ -187,8 +186,8 @@ def _get_submenu_from_menu(menu: QMenu, menu_title: str) -> Optional[QMenu]:
@pytest.fixture()
-def get_checked_menu_items() -> Callable[[QMenu], List[str]]:
- def _get_checked_menu_items(menu: QMenu) -> List[str]:
+def get_checked_menu_items() -> Callable[[QMenu], list[str]]:
+ def _get_checked_menu_items(menu: QMenu) -> list[str]:
return [
action.text()
for action in menu.actions()
diff --git a/test/integration/conftest.py b/test/integration/conftest.py
index 257a322..229d684 100644
--- a/test/integration/conftest.py
+++ b/test/integration/conftest.py
@@ -17,27 +17,27 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import TYPE_CHECKING, Generator, List
+from collections.abc import Generator
+from typing import TYPE_CHECKING
import pytest
from pytestqt.qtbot import QtBot
from qgis.core import QgsField, QgsProject, QgsVectorLayer, edit
from qgis.PyQt.QtCore import QVariant
-from quality_result_gui.ui.quality_errors_tree_filter_menu import (
- QualityErrorsTreeFilterMenu,
-)
-
if TYPE_CHECKING:
from quality_result_gui.api.quality_api_client import QualityResultClient
from quality_result_gui.api.types.quality_error import QualityError
from quality_result_gui.quality_error_manager import QualityResultManager
+ from quality_result_gui.ui.quality_errors_tree_filter_menu import (
+ QualityErrorsTreeFilterMenu,
+ )
@pytest.fixture()
def quality_result_manager(
qgis_new_project: None,
- bypass_log_if_fails: None,
+ _bypass_log_if_fails: None,
qtbot: QtBot,
mock_api_client: "QualityResultClient",
) -> Generator["QualityResultManager", None, None]:
@@ -55,7 +55,7 @@ def quality_result_manager(
@pytest.fixture()
def quality_result_manager_with_data(
quality_result_manager: "QualityResultManager",
- quality_errors: List["QualityError"],
+ quality_errors: list["QualityError"],
qtbot: QtBot,
) -> "QualityResultManager":
with qtbot.waitSignal(
@@ -70,7 +70,7 @@ def quality_result_manager_with_data(
@pytest.fixture()
def quality_result_manager_with_data_and_layer_mapping(
quality_result_manager: "QualityResultManager",
- quality_errors: List["QualityError"],
+ quality_errors: list["QualityError"],
qtbot: QtBot,
) -> Generator["QualityResultManager", None, None]:
layer = QgsVectorLayer("NoGeometry", "mock", "memory")
diff --git a/test/integration/test_checkbox_actions.py b/test/integration/test_checkbox_actions.py
index dc8b2fe..30f8fda 100644
--- a/test/integration/test_checkbox_actions.py
+++ b/test/integration/test_checkbox_actions.py
@@ -22,7 +22,6 @@
from qgis.core import QgsRectangle
from qgis.gui import QgisInterface
from qgis.PyQt.QtCore import QAbstractItemModel, QModelIndex
-
from quality_result_gui.api.types.quality_error import (
ERROR_PRIORITY_LABEL,
QualityErrorPriority,
@@ -75,7 +74,7 @@ def _count_children_rows(model: QAbstractItemModel, priority_index: QModelIndex)
"Only feature 2b89a0b0 within view extent",
],
)
-def test_filter_with_map_extent_check_box( # noqa: QGS105
+def test_filter_with_map_extent_check_box(
qgis_iface: QgisInterface,
quality_result_manager_with_data: QualityResultManager,
mocker: MockerFixture,
diff --git a/test/integration/test_filters.py b/test/integration/test_filters.py
index a75831f..e038969 100644
--- a/test/integration/test_filters.py
+++ b/test/integration/test_filters.py
@@ -17,14 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Callable, List, Optional
+from typing import Callable, Optional
import pytest
from pytestqt.qtbot import QtBot
from qgis.core import QgsFeature, QgsGeometry
from qgis.PyQt.QtCore import QModelIndex
from qgis.PyQt.QtWidgets import QAction, QMenu
-
from quality_result_gui.api.types.quality_error import (
ERROR_PRIORITY_LABEL,
ERROR_TYPE_LABEL,
@@ -89,7 +88,7 @@ def attribute_menu(
@pytest.fixture()
-def quality_errors_with_fence() -> List[QualityError]:
+def quality_errors_with_fence() -> list[QualityError]:
return [
QualityError(
QualityErrorPriority.FATAL,
@@ -134,7 +133,7 @@ def quality_errors_with_fence() -> List[QualityError]:
@pytest.fixture()
-def quality_errors_without_chimney_point() -> List[QualityError]:
+def quality_errors_without_chimney_point() -> list[QualityError]:
return [
QualityError(
QualityErrorPriority.FATAL,
@@ -166,7 +165,7 @@ def quality_errors_without_chimney_point() -> List[QualityError]:
@pytest.fixture()
-def quality_errors_without_building_part_area() -> List[QualityError]:
+def quality_errors_without_building_part_area() -> list[QualityError]:
return [
QualityError(
QualityErrorPriority.FATAL,
@@ -329,7 +328,7 @@ def test_reset_filters_action_restores_check_boxes(
],
)
def test_actions_are_connected_to_correct_implementation_methods_and_filters_are_applied(
- get_checked_menu_items: Callable[[QMenu], List[str]],
+ get_checked_menu_items: Callable[[QMenu], list[str]],
get_submenu_from_menu: Callable[[QMenu, str], Optional[QMenu]],
trigger_action: Callable[[QMenu, str], None],
error_type_menu: QMenu,
@@ -339,7 +338,7 @@ def test_actions_are_connected_to_correct_implementation_methods_and_filters_are
error_feature_types: list[str],
error_feature_attributes: list[str],
selected_filter_condition: str,
- selected_filter_values: List[str],
+ selected_filter_values: list[str],
expected_feature_types: list[str],
expected_feature_attributes: list[str],
expected_error_types: list[int],
@@ -482,11 +481,11 @@ def test_is_any_filter_active_returns_true_all_false_based_on_filter(
)
def test_filters_are_retained_when_data_changes(
qtbot: QtBot,
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
error_feature_types: list[str],
error_feature_attributes: list[str],
quality_result_manager_with_data: QualityResultManager,
- get_checked_menu_items: Callable[[QMenu], List[str]],
+ get_checked_menu_items: Callable[[QMenu], list[str]],
trigger_action: Callable[[QMenu, str], None],
feature_type_menu: QMenu,
attribute_menu: QMenu,
diff --git a/test/integration/test_tree_view.py b/test/integration/test_tree_view.py
index 595fce0..0a0d0df 100644
--- a/test/integration/test_tree_view.py
+++ b/test/integration/test_tree_view.py
@@ -18,7 +18,6 @@
# along with quality-result-gui. If not, see .
from copy import copy
-from typing import List
import pytest
from pytest_mock import MockerFixture
@@ -26,7 +25,6 @@
from qgis.core import QgsGeometry, QgsRectangle
from qgis.gui import QgisInterface
from qgis.PyQt.QtCore import QAbstractItemModel, QCoreApplication, QModelIndex, Qt
-
from quality_result_gui.api.types.quality_error import (
QualityError,
QualityErrorPriority,
@@ -109,7 +107,7 @@ def test_quality_error_tree_view_performance_with_big_dataset(
def test_quality_error_tree_view_updates_view_partially_when_data_is_refreshed(
quality_result_manager_with_data: QualityResultManager,
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
) -> None:
model = quality_result_manager_with_data.dock_widget.error_tree_view.model()
original_quality_errors = copy(quality_errors)
@@ -171,7 +169,7 @@ def test_quality_error_tree_view_updates_view_partially_when_data_is_refreshed(
"attribute-error-selected",
],
)
-def test_clicking_tree_view_row_zooms_to_feature_if_feature_or_quality_error_selected( # noqa: QGS105
+def test_clicking_tree_view_row_zooms_to_feature_if_feature_or_quality_error_selected(
quality_result_manager_with_data: QualityResultManager,
qtbot: QtBot,
qgis_iface: QgisInterface,
@@ -275,7 +273,7 @@ def test_changing_model_data_sends_error_geometries_to_visualizer(
)
assert m_add_or_replace_annotation.call_count == 2
- quality_errors: List[QualityError] = [
+ quality_errors: list[QualityError] = [
call_args[0][1] for call_args in m_add_or_replace_annotation.call_args_list
]
assert len(quality_errors) == 2
@@ -286,7 +284,7 @@ def test_changing_model_data_sends_error_geometries_to_visualizer(
def test_model_reset_expands_error_rows_recursively_on_tree_view(
quality_result_manager_with_data: QualityResultManager,
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
) -> None:
quality_result_manager_with_data._fetcher.results_received.emit(quality_errors)
diff --git a/test/unit/quality_result_gui/test_quality_data_fetcher.py b/test/unit/quality_result_gui/test_quality_data_fetcher.py
index c3aedcc..77b99a5 100644
--- a/test/unit/quality_result_gui/test_quality_data_fetcher.py
+++ b/test/unit/quality_result_gui/test_quality_data_fetcher.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -17,13 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Any, Generator, Optional
+from collections.abc import Generator
+from typing import Any, Optional
from unittest.mock import MagicMock
import pytest
from pytest_mock import MockerFixture
from pytestqt.qtbot import QtBot
-
from quality_result_gui.api.quality_api_client import (
QualityResultClient,
QualityResultClientError,
diff --git a/test/unit/quality_result_gui/test_quality_error_visualizer.py b/test/unit/quality_result_gui/test_quality_error_visualizer.py
index c9b1231..1bb3b9c 100644
--- a/test/unit/quality_result_gui/test_quality_error_visualizer.py
+++ b/test/unit/quality_result_gui/test_quality_error_visualizer.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Generator, List
+from collections.abc import Generator
from unittest.mock import ANY
import pytest
@@ -29,7 +29,6 @@
QgsRectangle,
)
from qgis.gui import QgisInterface
-
from quality_result_gui import SelectionType
from quality_result_gui.api.types.quality_error import (
QualityError,
@@ -58,7 +57,7 @@ def visualizer() -> Generator[QualityErrorVisualizer, None, None]:
@pytest.fixture()
-def visualized_errors() -> List[QualityError]:
+def visualized_errors() -> list[QualityError]:
return [
_create_test_quality_error(
QualityErrorPriority.FATAL, "1", QgsGeometry.fromWkt("Point(1 1)")
@@ -101,7 +100,7 @@ def test_add_new_errors_adds_geometries_to_annotation_layer(
assert layer is not None
- for key in visualizer._quality_error_layer._annotation_ids.keys():
+ for key in visualizer._quality_error_layer._annotation_ids:
assert key in [
"1",
"2",
@@ -109,7 +108,7 @@ def test_add_new_errors_adds_geometries_to_annotation_layer(
assert len(layer.items()) == 2
- for key in layer.items().keys():
+ for key in layer.items():
assert key in sum(visualizer._quality_error_layer._annotation_ids.values(), [])
assert layer.item(key).geometry().isEmpty() is False
@@ -117,7 +116,6 @@ def test_add_new_errors_adds_geometries_to_annotation_layer(
def test_add_new_errors_does_nothing_with_empty_input(
visualizer: QualityErrorVisualizer,
):
-
# Test
visualizer.add_new_errors([])
@@ -127,7 +125,6 @@ def test_add_new_errors_does_nothing_with_empty_input(
def test_add_new_errors_does_nothing_with_empty_input_geometry(
visualizer: QualityErrorVisualizer,
):
-
# Test
visualizer.add_new_errors(
[_create_test_quality_error(QualityErrorPriority.FATAL, "1", QgsGeometry())]
@@ -139,7 +136,6 @@ def test_add_new_errors_does_nothing_with_empty_input_geometry(
def test_add_new_errors_works_with_multiple_geoms_with_same_geometry_type(
visualizer: QualityErrorVisualizer,
):
-
priority = QualityErrorPriority.FATAL
errors = [
_create_test_quality_error(priority, "1", QgsGeometry.fromWkt("Point(2 3)")),
@@ -166,7 +162,7 @@ def test_add_new_errors_works_with_multiple_geoms_with_same_geometry_type(
)
def test_remove_errors_removes_features_from_annotation_layer(
visualizer: QualityErrorVisualizer,
- visualized_errors: List[QualityError],
+ visualized_errors: list[QualityError],
remove_selected_error: bool,
):
visualizer.add_new_errors(visualized_errors)
@@ -184,7 +180,7 @@ def test_remove_errors_removes_features_from_annotation_layer(
if remove_selected_error:
assert get_num_visualized_features(visualizer) == num_errors_before_removal - 3
- for key in visualizer._quality_error_layer._annotation_ids.keys():
+ for key in visualizer._quality_error_layer._annotation_ids:
assert key == visualized_errors[2].unique_identifier
else:
assert get_num_visualized_features(visualizer) == num_errors_before_removal - 2
@@ -195,7 +191,7 @@ def test_remove_errors_removes_features_from_annotation_layer(
def test_remove_errors_does_nothing_with_empty_input(
- visualizer: QualityErrorVisualizer, visualized_errors: List[QualityError]
+ visualizer: QualityErrorVisualizer, visualized_errors: list[QualityError]
):
visualizer.add_new_errors(visualized_errors)
visualizer.refresh_selected_error(visualized_errors[0])
@@ -213,7 +209,7 @@ def test_remove_errors_does_nothing_with_empty_input(
def test_hide_errors_changes_quality_layer_visibility(
- visualizer: QualityErrorVisualizer, visualized_errors: List[QualityError]
+ visualizer: QualityErrorVisualizer, visualized_errors: list[QualityError]
):
root: QgsLayerTree = QgsProject.instance().layerTreeRoot()
@@ -235,9 +231,8 @@ def test_hide_errors_changes_quality_layer_visibility(
def test_add_new_errors_replaces_annotation_features_if_same_id(
visualizer: QualityErrorVisualizer,
- visualized_errors: List[QualityError],
+ visualized_errors: list[QualityError],
):
-
visualizer.add_new_errors(visualized_errors)
assert get_num_visualized_features(visualizer) == len(visualized_errors)
@@ -254,9 +249,8 @@ def test_add_new_errors_replaces_annotation_features_if_same_id(
def test_refresh_selected_errors_replaces_selected_features_only(
- visualizer: QualityErrorVisualizer, visualized_errors: List[QualityError]
+ visualizer: QualityErrorVisualizer, visualized_errors: list[QualityError]
):
-
visualizer.add_new_errors(visualized_errors)
visualizer.refresh_selected_error(visualized_errors[0])
@@ -339,11 +333,11 @@ def test_on_error_selected(
"empty list",
],
)
-def test_zoom_to_geometries_and_flash( # noqa: QGS105
+def test_zoom_to_geometries_and_flash(
visualizer: QualityErrorVisualizer,
qgis_iface: QgisInterface,
preserve_scale: bool,
- input_geoms: List[QgsGeometry],
+ input_geoms: list[QgsGeometry],
should_zoom_to_feature: bool,
):
qgis_iface.mapCanvas().setExtent(QgsRectangle(100, 100, 200, 200))
diff --git a/test/unit/quality_result_gui/test_quality_errors_filters.py b/test/unit/quality_result_gui/test_quality_errors_filters.py
index 10f613c..23fc4a8 100644
--- a/test/unit/quality_result_gui/test_quality_errors_filters.py
+++ b/test/unit/quality_result_gui/test_quality_errors_filters.py
@@ -22,7 +22,6 @@
import pytest
from qgis.PyQt.QtWidgets import QAction, QMenu
-
from quality_result_gui.api.types.quality_error import ERROR_TYPE_LABEL
from quality_result_gui.quality_errors_filters import ErrorTypeFilter, FilterMenu
@@ -154,7 +153,6 @@ def test_deselect_action_unchecks_all(
get_action_from_menu: Callable[[QMenu, str], Optional[QAction]],
trigger_action: Callable[[QMenu, str], None],
):
-
error_type_filter_menu = ErrorTypeFilter()
error_type_filter_menu._refresh_error_type_filters(ERROR_TYPE_LABEL)
diff --git a/test/unit/quality_result_gui/test_quality_errors_manager.py b/test/unit/quality_result_gui/test_quality_errors_manager.py
index 6a7d820..92e3da5 100644
--- a/test/unit/quality_result_gui/test_quality_errors_manager.py
+++ b/test/unit/quality_result_gui/test_quality_errors_manager.py
@@ -17,7 +17,8 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Callable, Generator, List, Optional
+from collections.abc import Generator
+from typing import Callable, Optional
from unittest.mock import MagicMock
import pytest
@@ -27,7 +28,6 @@
from qgis.gui import QgsGui
from qgis.PyQt.QtCore import QModelIndex, Qt
from qgis.PyQt.QtWidgets import QMenu
-
from quality_result_gui.api.quality_api_client import QualityResultClient
from quality_result_gui.api.types.quality_error import QualityError
from quality_result_gui.configuration import QualityLayerStyleConfig
@@ -56,7 +56,7 @@ def quality_result_manager(
@pytest.fixture()
def quality_result_manager_with_data(
quality_result_manager: QualityResultManager,
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
qtbot: QtBot,
) -> QualityResultManager:
with qtbot.waitSignal(
@@ -127,7 +127,6 @@ def test_show_dock_widget_starts_fetcher_and_shows_widget(
def test_close_and_reopen_preserves_error_visibility_on_map(
mock_api_client: QualityResultClient,
) -> None:
-
quality_result_manager = QualityResultManager(mock_api_client, None)
def _check_quality_layer_visibility(expected_visibility: bool) -> None:
@@ -184,7 +183,6 @@ def test_model_set_data_user_processed(
expected_callback_value: bool,
callback_called: bool,
) -> None:
-
quality_result_manager_with_data.error_checked.connect(m_user_processed_callback)
model = quality_result_manager_with_data._styled_model
@@ -206,7 +204,7 @@ def test_model_set_data_user_processed(
def test_override_quality_layer_style_changes_annotation_style(
qtbot: QtBot,
mock_api_client: QualityResultClient,
- single_quality_error: List[QualityError],
+ single_quality_error: list[QualityError],
):
class MockStyle(QualityLayerStyleConfig):
def create_error_symbol(self, quality_error: QualityError) -> ErrorSymbol:
@@ -237,7 +235,6 @@ def create_error_symbol(self, quality_error: QualityError) -> ErrorSymbol:
def test_shortcut_for_toggle_errors_is_unregistered_after_unload(
quality_result_manager: QualityResultManager,
) -> None:
-
quality_result_manager.show_dock_widget()
shortcut_name = (
diff --git a/test/unit/quality_result_gui/test_quality_errors_tree_model.py b/test/unit/quality_result_gui/test_quality_errors_tree_model.py
index 2cad113..cc10f07 100644
--- a/test/unit/quality_result_gui/test_quality_errors_tree_model.py
+++ b/test/unit/quality_result_gui/test_quality_errors_tree_model.py
@@ -17,12 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Dict, List, NamedTuple, Optional, Set
+from typing import NamedTuple, Optional
import pytest
from pytestqt.modeltest import ModelTester
from qgis.PyQt.QtCore import QAbstractItemModel, QModelIndex, Qt, QVariant
-
from quality_result_gui.api.types.quality_error import (
ERROR_TYPE_LABEL,
QualityError,
@@ -44,17 +43,17 @@
)
-def _feature_type_filters(quality_errors: List[QualityError]) -> Set[str]:
+def _feature_type_filters(quality_errors: list[QualityError]) -> set[str]:
return get_error_feature_types(quality_errors)
def _feature_attribute_filters(
- quality_errors: List[QualityError],
-) -> Set[str]:
+ quality_errors: list[QualityError],
+) -> set[str]:
return get_error_feature_attributes(quality_errors)
-def _error_type_filters() -> Set[QualityErrorType]:
+def _error_type_filters() -> set[QualityErrorType]:
return set(QualityErrorType)
@@ -126,7 +125,7 @@ def _priority_1_feature_type_1_feature_1_error_2_description_index(
@pytest.fixture()
def feature_type_filter(
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
) -> FeatureTypeFilter:
feature_type_filter = FeatureTypeFilter()
for feature_type in get_error_feature_types(quality_errors):
@@ -141,10 +140,9 @@ def base_model() -> QualityErrorsTreeBaseModel:
@pytest.fixture()
def model(
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
base_model: QualityErrorsTreeBaseModel,
) -> FilterByExtentProxyModel:
-
styled_model = StyleProxyModel(None)
styled_model.setSourceModel(base_model)
@@ -174,9 +172,8 @@ class ModelAndFilters(NamedTuple):
@pytest.fixture()
def filter_proxy_model_and_filters(
base_model: QualityErrorsTreeBaseModel,
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
) -> ModelAndFilters:
-
filter_model = FilterProxyModel()
filter_model.setSourceModel(base_model)
@@ -206,7 +203,7 @@ def filter_proxy_model_and_filters(
def test_base_model(
base_model: QualityErrorsTreeBaseModel,
qtmodeltester: ModelTester,
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
) -> None:
base_model.refresh_model(quality_errors)
@@ -323,7 +320,6 @@ def test_model_header_data(model: FilterByExtentProxyModel):
def test_total_number_of_errors_is_shown_in_header(
filter_proxy_model_and_filters: ModelAndFilters,
):
-
(
_,
model,
@@ -572,11 +568,11 @@ def test_model_checkable_flags(model: FilterByExtentProxyModel):
)
def test_model_data_count_changes_when_filter_is_applied(
filter_proxy_model_and_filters: ModelAndFilters,
- quality_errors: List[QualityError],
- accepted_error_types: Optional[Set[QualityErrorType]],
- accepted_feature_types: Optional[Set[str]],
- accepted_attribute_names: Optional[Set[str]],
- expected_counts: Dict[str, int],
+ quality_errors: list[QualityError],
+ accepted_error_types: Optional[set[QualityErrorType]],
+ accepted_feature_types: Optional[set[str]],
+ accepted_attribute_names: Optional[set[str]],
+ expected_counts: dict[str, int],
):
accepted_feature_types = (
accepted_feature_types
@@ -585,9 +581,7 @@ def test_model_data_count_changes_when_filter_is_applied(
)
for (
filter_value
- ) in (
- filter_proxy_model_and_filters.feature_type_filter._filter_value_action_map.keys()
- ):
+ ) in filter_proxy_model_and_filters.feature_type_filter._filter_value_action_map:
filter_proxy_model_and_filters.feature_type_filter._sync_filtered(
filter_value, filter_value in accepted_feature_types
)
@@ -599,9 +593,7 @@ def test_model_data_count_changes_when_filter_is_applied(
)
for (
filter_value
- ) in (
- filter_proxy_model_and_filters.attribute_name_filter._filter_value_action_map.keys()
- ):
+ ) in filter_proxy_model_and_filters.attribute_name_filter._filter_value_action_map:
filter_proxy_model_and_filters.attribute_name_filter._sync_filtered(
filter_value, filter_value in accepted_attribute_names
)
@@ -613,9 +605,7 @@ def test_model_data_count_changes_when_filter_is_applied(
)
for (
filter_value
- ) in (
- filter_proxy_model_and_filters.error_type_filter._filter_value_action_map.keys()
- ):
+ ) in filter_proxy_model_and_filters.error_type_filter._filter_value_action_map:
filter_proxy_model_and_filters.error_type_filter._sync_filtered(
filter_value, filter_value in accepted_error_types
)
@@ -645,7 +635,7 @@ def test_model_data_count_changes_when_filter_is_applied(
def test_refresh_model_updates_data_partially_when_data_is_refreshed(
base_model: QualityErrorsTreeBaseModel,
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
):
base_model.refresh_model(quality_errors)
@@ -669,7 +659,7 @@ def test_refresh_model_updates_data_partially_when_data_is_refreshed(
def test_refresh_model_does_nothing_if_data_does_not_change(
base_model: QualityErrorsTreeBaseModel,
- quality_errors: List[QualityError],
+ quality_errors: list[QualityError],
):
base_model.refresh_model(quality_errors)
@@ -691,7 +681,6 @@ def test_refresh_model_does_nothing_if_data_does_not_change(
def test_no_rows_visible_when_all_user_processed(
filter_proxy_model_and_filters: ModelAndFilters,
):
-
model = FilterByShowUserProcessedProxyModel()
model.setSourceModel(filter_proxy_model_and_filters.filter_proxy_model)
diff --git a/test/unit/quality_result_gui/test_quality_layer.py b/test/unit/quality_result_gui/test_quality_layer.py
index 69f0bde..e5717e1 100644
--- a/test/unit/quality_result_gui/test_quality_layer.py
+++ b/test/unit/quality_result_gui/test_quality_layer.py
@@ -17,12 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Iterator, List
+from collections.abc import Iterator
from unittest.mock import ANY
import pytest
from qgis.core import QgsAnnotationLayer, QgsGeometry, QgsProject
-
from quality_result_gui.api.types.quality_error import QualityErrorPriority
from quality_result_gui.quality_error_visualizer import QualityError
from quality_result_gui.quality_layer import QualityErrorLayer
@@ -37,7 +36,7 @@ def _create_test_quality_error(
@pytest.fixture()
-def quality_layer(qgis_new_project) -> QualityErrorLayer:
+def quality_layer(qgis_new_project: None) -> QualityErrorLayer:
return QualityErrorLayer()
@@ -140,7 +139,7 @@ def test_add_or_replace_annotation_with_new_quality_errors(
assert list(quality_layer_created._annotation_ids.keys()) == ["1"]
assert len(annotation_layer.items()) == num_resulting_annotations
- for key in annotation_layer.items().keys():
+ for key in annotation_layer.items():
assert key in sum(quality_layer_created._annotation_ids.values(), [])
assert annotation_layer.item(key).geometry().isEmpty() is False
@@ -192,7 +191,7 @@ def test_add_or_replace_annotation_with_updated_quality_errors(
old_geom: QgsGeometry,
num_old_items: int,
new_geom: QgsGeometry,
- expected_geoms_as_wkt: List[str],
+ expected_geoms_as_wkt: list[str],
):
assert not old_geom.isNull(), "Input WKT was not valid"
assert not new_geom.isNull(), "Input WKT was not valid"
@@ -211,7 +210,7 @@ def test_add_or_replace_annotation_with_updated_quality_errors(
assert len(annotation_layer.items()) == len(expected_geoms_as_wkt)
- for key in annotation_layer.items().keys():
+ for key in annotation_layer.items():
assert annotation_layer.item(key).geometry().asWkt() in expected_geoms_as_wkt
diff --git a/test/unit/quality_result_gui/ui/test_quality_errors_dock.py b/test/unit/quality_result_gui/ui/test_quality_errors_dock.py
index e15b168..36bee83 100644
--- a/test/unit/quality_result_gui/ui/test_quality_errors_dock.py
+++ b/test/unit/quality_result_gui/ui/test_quality_errors_dock.py
@@ -17,15 +17,18 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
+from typing import TYPE_CHECKING
+
import pytest
from pytest_mock import MockerFixture
from pytestqt.qtbot import QtBot
from qgis.gui import QgsGui
from qgis.PyQt.QtCore import Qt
-from qgis.PyQt.QtWidgets import QShortcut
-
from quality_result_gui.ui.quality_errors_dock import QualityErrorsDockWidget
+if TYPE_CHECKING:
+ from qgis.PyQt.QtWidgets import QShortcut
+
@pytest.fixture()
def dock_widget(qtbot: QtBot) -> QualityErrorsDockWidget:
@@ -53,7 +56,6 @@ def test_quality_errors_dock_opens_and_closes(dock_widget: QualityErrorsDockWidg
],
)
def test_update_filter_menu_icon_state(mocker: MockerFixture, has_filters_active: bool):
-
dock_widget = QualityErrorsDockWidget()
m_is_any_filter_active = mocker.patch.object(
dock_widget.filter_menu,
@@ -72,7 +74,6 @@ def test_update_filter_menu_icon_state(mocker: MockerFixture, has_filters_active
def test_shortcut_for_toggle_errors_toggles_checkbox(
dock_widget: QualityErrorsDockWidget,
) -> None:
-
dock_widget.show()
shortcut = dock_widget.shortcut_for_toggle_errors
diff --git a/test/unit/quality_result_gui_plugin/test_plugin.py b/test/unit/quality_result_gui_plugin/test_plugin.py
index 50164b6..3871aa5 100644
--- a/test/unit/quality_result_gui_plugin/test_plugin.py
+++ b/test/unit/quality_result_gui_plugin/test_plugin.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2022 National Land Survey of Finland
+# Copyright (C) 2022-2023 National Land Survey of Finland
# (https://www.maanmittauslaitos.fi/en).
#
#
@@ -17,13 +17,12 @@
# You should have received a copy of the GNU General Public License
# along with quality-result-gui. If not, see .
-from typing import Iterator
+from collections.abc import Iterator
import pytest
from pytest_mock import MockerFixture
from qgis.core import QgsSettings
from qgis.utils import iface
-
from quality_result_gui_plugin import classFactory
from quality_result_gui_plugin.dev_tools.dev_tools_dialog import DevToolsDialog
from quality_result_gui_plugin.plugin import QualityResultGuiPlugin