From 64ad100194ebd107ab1a06785f7c37e53b42d908 Mon Sep 17 00:00:00 2001 From: Joonalai Date: Fri, 15 Dec 2023 15:57:36 +0200 Subject: [PATCH] Update QgisInterface class, refactor and improve tests [#24] --- .gitignore | 1 + CHANGELOG.md | 4 + pyproject.toml | 2 +- src/pytest_qgis/pytest_qgis.py | 3 +- src/pytest_qgis/qgis_interface.py | 564 +++++++++++++++--------------- tests/test_pytest_qgis.py | 33 -- tests/test_qgis_interface.py | 70 ++++ 7 files changed, 364 insertions(+), 313 deletions(-) create mode 100644 tests/test_qgis_interface.py diff --git a/.gitignore b/.gitignore index d427f94..e5d1789 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,4 @@ target/ /tests/data/db.gpkg-shm /tests/data/db.gpkg-wal /tests/data/*.tif.aux.xml +/Makefile diff --git a/CHANGELOG.md b/CHANGELOG.md index f011dd1..84941b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Unreleased +## Fixes + +* Make stub QgisInterface and MockMessageBar inherit real interfaces + # Version 2.0.0 (29-11-2023) ## New Features diff --git a/pyproject.toml b/pyproject.toml index 06452b4..c7ed3cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -122,7 +122,7 @@ ban-relative-imports = "all" [tool.ruff.per-file-ignores] "src/pytest_qgis/pytest_qgis.py"=["PLR2004"] # TODO: Fix magic values. Remove this after. -"src/pytest_qgis/qgis_interface.py" = ["N802", "N803", "N815"] +"src/pytest_qgis/qgis_interface.py" = ["N802", "N803", "N815", "ARG002"] "src/pytest_qgis/mock_qgis_classes.py" = ["N802", "N803"] "tests/*" = [ "ANN001", diff --git a/src/pytest_qgis/pytest_qgis.py b/src/pytest_qgis/pytest_qgis.py index 3b06657..477fc82 100644 --- a/src/pytest_qgis/pytest_qgis.py +++ b/src/pytest_qgis/pytest_qgis.py @@ -30,7 +30,6 @@ import pytest from qgis.core import Qgis, QgsApplication, QgsProject, QgsRectangle, QgsVectorLayer -from qgis.gui import QgisInterface as QgisInterfaceOrig from qgis.gui import QgsGui, QgsLayerTreeMapCanvasBridge, QgsMapCanvas from qgis.PyQt import QtCore, QtWidgets, sip from qgis.PyQt.QtCore import QCoreApplication @@ -185,7 +184,7 @@ def qgis_version() -> int: @pytest.fixture(scope="session") -def qgis_iface() -> QgisInterfaceOrig: +def qgis_iface() -> QgisInterface: assert _IFACE return _IFACE diff --git a/src/pytest_qgis/qgis_interface.py b/src/pytest_qgis/qgis_interface.py index 840b376..140b4f1 100644 --- a/src/pytest_qgis/qgis_interface.py +++ b/src/pytest_qgis/qgis_interface.py @@ -1,3 +1,5 @@ +# mypy: disable-error-code="empty-body" + """QGIS plugin implementation. .. note:: This program is free software; you can redistribute it and/or modify @@ -65,17 +67,19 @@ LOGGER = logging.getLogger("QGIS") -@typing.no_type_check # TODO: remove this later +@typing.no_type_check # TODO: remove this when most of the methods are implemented class QgisInterface(QgisAbstractInterface): """ Class to expose QGIS objects and functions to plugins. This class is here for enabling us to run unit tests only, so some of the methods are simply stubs. + + Feel free to add more content. """ - currentLayerChanged = QtCore.pyqtSignal(QgsMapCanvas) # noqa: N815 - newProjectCreated = pyqtSignal() # noqa: N815 + currentLayerChanged = QtCore.pyqtSignal(QgsMapCanvas) + newProjectCreated = pyqtSignal() layerSavedAs: ClassVar[QtCore.pyqtSignal] projectRead: ClassVar[QtCore.pyqtSignal] @@ -85,6 +89,9 @@ class QgisInterface(QgisAbstractInterface): layoutDesignerOpened: ClassVar[QtCore.pyqtSignal] currentThemeChanged: ClassVar[QtCore.pyqtSignal] + # Simple fields + gps_panel_connection: Optional[qgis_core.QgsGpsConnection] = None + def __init__( self, canvas: QgsMapCanvas, @@ -123,9 +130,6 @@ def addLayers(self, layers: list[QgsMapLayer]) -> None: .. note:: The QgsInterface api does not include this method, it is added here as a helper to facilitate testing. """ - # LOGGER.debug('addLayers called on qgis_interface') - # LOGGER.debug('Number of layers being added: %s' % len(layers)) - # LOGGER.debug('Layer Count Before: %s' % len(self.canvas.layers())) current_layers = self.canvas.layers() final_layers = [] for layer in current_layers: @@ -135,7 +139,6 @@ def addLayers(self, layers: list[QgsMapLayer]) -> None: self._layers = final_layers self.canvas.setLayers(final_layers) - # LOGGER.debug('Layer Count After: %s' % len(self.canvas.layers())) @pyqtSlot() def removeAllLayers(self) -> None: @@ -154,7 +157,7 @@ def newProject(self, promptToSaveFlag: bool = False) -> bool: relation_manager: QgsRelationManager = instance.relationManager() for relation in relation_manager.relations(): relation_manager.removeRelation(relation) - self._layers = [] + self._layers.clear() self._messageBar.clear_messages() self.newProjectCreated.emit() return True @@ -162,172 +165,172 @@ def newProject(self, promptToSaveFlag: bool = False) -> bool: def setGpsPanelConnection( self, connection: Optional[qgis_core.QgsGpsConnection] ) -> None: - ... + self.gps_panel_connection = connection def browserModel(self) -> Optional["QgsBrowserGuiModel"]: - ... + pass def askForDatumTransform( self, sourceCrs: qgis_core.QgsCoordinateReferenceSystem, destinationCrs: qgis_core.QgsCoordinateReferenceSystem, ) -> bool: - ... + pass def invalidateLocatorResults(self) -> None: - ... + pass def deregisterLocatorFilter( self, filter: Optional[qgis_core.QgsLocatorFilter] ) -> None: - ... + pass def registerLocatorFilter( self, filter: Optional[qgis_core.QgsLocatorFilter] ) -> None: - ... + pass def locatorSearch(self, searchText: Optional[str]) -> None: - ... + pass def preloadForm(self, uifile: Optional[str]) -> None: - ... + pass def getFeatureForm( self, layer: Optional[qgis_core.QgsVectorLayer], f: qgis_core.QgsFeature ) -> Optional["QgsAttributeDialog"]: - ... + pass def openFeatureForm( self, - l: Optional[qgis_core.QgsVectorLayer], + l: Optional[qgis_core.QgsVectorLayer], # noqa: E741 f: qgis_core.QgsFeature, updateFeatureOnly: bool = ..., showModal: bool = ..., ) -> bool: - ... + pass def openURL(self, url: Optional[str], useQgisDocDirectory: bool = ...) -> None: - ... + pass def unregisterCustomLayoutDropHandler( self, handler: Optional["QgsLayoutCustomDropHandler"] ) -> None: - ... + pass def registerCustomLayoutDropHandler( self, handler: Optional["QgsLayoutCustomDropHandler"] ) -> None: - ... + pass def unregisterCustomProjectOpenHandler( self, handler: Optional["QgsCustomProjectOpenHandler"] ) -> None: - ... + pass def registerCustomProjectOpenHandler( self, handler: Optional["QgsCustomProjectOpenHandler"] ) -> None: - ... + pass def unregisterCustomDropHandler( self, handler: Optional["QgsCustomDropHandler"] ) -> None: - ... + pass def registerCustomDropHandler( self, handler: Optional["QgsCustomDropHandler"] ) -> None: - ... + pass def unregisterMapToolHandler( self, handler: Optional["QgsAbstractMapToolHandler"] ) -> None: - ... + pass def registerMapToolHandler( self, handler: Optional["QgsAbstractMapToolHandler"] ) -> None: - ... + pass def unregisterApplicationExitBlocker( self, blocker: Optional["QgsApplicationExitBlockerInterface"] ) -> None: - ... + pass def registerApplicationExitBlocker( self, blocker: Optional["QgsApplicationExitBlockerInterface"] ) -> None: - ... + pass def unregisterDevToolWidgetFactory( self, factory: Optional["QgsDevToolWidgetFactory"] ) -> None: - ... + pass def registerDevToolWidgetFactory( self, factory: Optional["QgsDevToolWidgetFactory"] ) -> None: - ... + pass def unregisterProjectPropertiesWidgetFactory( self, factory: Optional["QgsOptionsWidgetFactory"] ) -> None: - ... + pass def registerProjectPropertiesWidgetFactory( self, factory: Optional["QgsOptionsWidgetFactory"] ) -> None: - ... + pass def unregisterOptionsWidgetFactory( self, factory: Optional["QgsOptionsWidgetFactory"] ) -> None: - ... + pass def registerOptionsWidgetFactory( self, factory: Optional["QgsOptionsWidgetFactory"] ) -> None: - ... + pass def unregisterMapLayerConfigWidgetFactory( self, factory: Optional["QgsMapLayerConfigWidgetFactory"] ) -> None: - ... + pass def registerMapLayerConfigWidgetFactory( self, factory: Optional["QgsMapLayerConfigWidgetFactory"] ) -> None: - ... + pass def unregisterMainWindowAction(self, action: Optional[QtWidgets.QAction]) -> bool: - ... + pass def registerMainWindowAction( self, action: Optional[QtWidgets.QAction], defaultShortcut: Optional[str] ) -> bool: - ... + pass def removeWindow(self, action: Optional[QtWidgets.QAction]) -> None: - ... + pass def addWindow(self, action: Optional[QtWidgets.QAction]) -> None: - ... + pass def showAttributeTable( self, - l: Optional[qgis_core.QgsVectorLayer], + l: Optional[qgis_core.QgsVectorLayer], # noqa: E741 filterExpression: Optional[str] = ..., ) -> Optional[QtWidgets.QDialog]: - ... + pass def showLayerProperties( self, layer: Optional[qgis_core.QgsMapLayer], page: Optional[str] = ... ) -> None: - ... + pass def removeDockWidget(self, dockwidget: Optional[QtWidgets.QDockWidget]) -> None: - ... + pass def addTabifiedDockWidget( self, @@ -336,114 +339,114 @@ def addTabifiedDockWidget( tabifyWith: typing.Iterable[Optional[str]] = ..., raiseTab: bool = ..., ) -> None: - ... + pass def addDockWidget( self, area: QtCore.Qt.DockWidgetArea, dockwidget: Optional[QtWidgets.QDockWidget], ) -> None: - ... + pass def removePluginMeshMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def addPluginToMeshMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def removePluginWebMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def addPluginToWebMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def removePluginVectorMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def addPluginToVectorMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def removePluginRasterMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def addPluginToRasterMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def removePluginDatabaseMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def addPluginToDatabaseMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def removeAddLayerAction(self, action: Optional[QtWidgets.QAction]) -> None: - ... + pass def insertAddLayerAction(self, action: Optional[QtWidgets.QAction]) -> None: - ... + pass def removePluginMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def addPluginToMenu( self, name: Optional[str], action: Optional[QtWidgets.QAction] ) -> None: - ... + pass def saveStyleSheetOptions(self, opts: dict[Optional[str], Any]) -> None: - ... + pass def buildStyleSheet(self, opts: dict[Optional[str], Any]) -> None: - ... + pass def showProjectPropertiesDialog(self, currentPage: Optional[str] = ...) -> None: - ... + pass def showOptionsDialog( self, parent: Optional[QtWidgets.QWidget] = ..., currentPage: Optional[str] = ..., ) -> None: - ... + pass def openLayoutDesigner( self, layout: Optional[qgis_core.QgsMasterLayoutInterface] ) -> Optional["QgsLayoutDesignerInterface"]: - ... + pass def showLayoutManager(self) -> None: - ... + pass def addUserInputWidget(self, widget: Optional[QtWidgets.QWidget]) -> None: - ... + pass def openMessageLog(self) -> None: - ... + pass @typing.overload def addToolBar(self, name: Optional[str]) -> Optional[QtWidgets.QToolBar]: - ... + pass @typing.overload def addToolBar( @@ -451,7 +454,7 @@ def addToolBar( toolbar: Optional[QtWidgets.QToolBar], area: Optional[QtCore.Qt.ToolBarArea] = None, ) -> None: - ... + pass def addToolBar( self, @@ -468,65 +471,65 @@ def addToolBar( return _toolbar if isinstance(toolbar, str) else None def removeWebToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> None: - ... + pass def addWebToolBarWidget( self, widget: Optional[QtWidgets.QWidget] ) -> Optional[QtWidgets.QAction]: - ... + pass def addWebToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> int: - ... + pass def removeDatabaseToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> None: - ... + pass def addDatabaseToolBarWidget( self, widget: Optional[QtWidgets.QWidget] ) -> Optional[QtWidgets.QAction]: - ... + pass def addDatabaseToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> int: - ... + pass def removeVectorToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> None: - ... + pass def addVectorToolBarWidget( self, widget: Optional[QtWidgets.QWidget] ) -> Optional[QtWidgets.QAction]: - ... + pass def addVectorToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> int: - ... + pass def removeRasterToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> None: - ... + pass def addRasterToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> int: - ... + pass def addRasterToolBarWidget( self, widget: Optional[QtWidgets.QWidget] ) -> Optional[QtWidgets.QAction]: - ... + pass def removeToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> None: - ... + pass def addToolBarWidget( self, widget: Optional[QtWidgets.QWidget] ) -> Optional[QtWidgets.QAction]: - ... + pass def addToolBarIcon(self, qAction: Optional[QtWidgets.QAction]) -> int: - ... + pass def pasteFromClipboard(self, a0: Optional[qgis_core.QgsMapLayer]) -> None: - ... + pass def copySelectionToClipboard(self, a0: Optional[qgis_core.QgsMapLayer]) -> None: - ... + pass def setActiveLayer(self, layer: Optional[qgis_core.QgsMapLayer]) -> bool: """ @@ -538,42 +541,49 @@ def setActiveLayer(self, layer: Optional[qgis_core.QgsMapLayer]) -> bool: return False def reloadConnections(self) -> None: - ... + pass def addProject(self, project: Optional[str]) -> bool: - ... + pass def addTiledSceneLayer( self, url: Optional[str], baseName: Optional[str], providerKey: Optional[str] - ) -> Optional[qgis_core.QgsTiledSceneLayer]: - ... + ) -> Optional["qgis_core.QgsTiledSceneLayer"]: + pass def addPointCloudLayer( self, url: Optional[str], baseName: Optional[str], providerKey: Optional[str] ) -> Optional[qgis_core.QgsPointCloudLayer]: - ... + pass def addVectorTileLayer( self, url: Optional[str], baseName: Optional[str] ) -> Optional[qgis_core.QgsVectorTileLayer]: - ... + pass def addMeshLayer( self, url: Optional[str], baseName: Optional[str], providerKey: Optional[str] ) -> Optional[qgis_core.QgsMeshLayer]: - ... + pass @typing.overload def addRasterLayer( - self, rasterLayerPath: Optional[str], baseName: Optional[str] = ... + self, rasterLayerPath: Optional[str], baseName: Optional[str] = None ) -> Optional[qgis_core.QgsRasterLayer]: - ... + pass @typing.overload def addRasterLayer( self, url: Optional[str], layerName: Optional[str], providerKey: Optional[str] ) -> Optional[qgis_core.QgsRasterLayer]: - ... + pass + + def addRasterLayer( + self, *args: str, **kwargs: dict[str, str] + ) -> Optional[qgis_core.QgsRasterLayer]: + layer = qgis_core.QgsRasterLayer(*args, **kwargs) + self.addLayers([layer]) + return layer def addVectorLayer( self, @@ -586,497 +596,497 @@ def addVectorLayer( return layer def zoomToActiveLayer(self) -> None: - ... + pass def zoomToNext(self) -> None: - ... + pass def zoomToPrevious(self) -> None: - ... + pass def zoomFull(self) -> None: - ... + pass - def userProfileManager(self) -> Optional[qgis_core.QgsUserProfileManager]: - ... + def userProfileManager(self) -> Optional["qgis_core.QgsUserProfileManager"]: + pass def layerTreeInsertionPoint( self, ) -> qgis_core.QgsLayerTreeRegistryBridge.InsertionPoint: - ... + pass def takeAppScreenShots( self, saveDirectory: Optional[str], categories: int = ... ) -> None: - ... + pass def statusBarIface(self) -> Optional["QgsStatusBar"]: - ... + pass def messageTimeout(self) -> int: - ... + pass def vectorLayerTools(self) -> Optional[qgis_core.QgsVectorLayerTools]: - ... + pass def actionRegularPolygonCenterCorner(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRegularPolygonCenterPoint(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRegularPolygon2Points(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRectangle3PointsProjected(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRectangle3PointsDistance(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRectangleExtent(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRectangleCenterPoint(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionEllipseFoci(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionEllipseExtent(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionEllipseCenterPoint(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionEllipseCenter2Points(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCircleCenterPoint(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCircle2TangentsPoint(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCircle3Tangents(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCircle3Points(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCircle2Points(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAbout(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCheckQgisVersion(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionQgisHomePage(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionHelpContents(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCustomProjection(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionOptions(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionToggleFullScreen(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionShowPythonDialog(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionPluginListSeparator(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionManagePlugins(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionShowSelectedLayers(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionHideDeselectedLayers(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionToggleSelectedLayersIndependently(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionToggleSelectedLayers(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionHideSelectedLayers(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionShowAllLayers(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionHideAllLayers(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRemoveAllFromOverview(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddAllToOverview(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddToOverview(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionLayerProperties(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionDuplicateLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionLayerSaveAs(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCancelAllEdits(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCancelEdits(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRollbackAllEdits(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionRollbackEdits(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSaveAllEdits(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSaveEdits(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAllEdits(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSaveActiveLayerEdits(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionToggleEditing(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionOpenStatisticalSummary(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionOpenFieldCalculator(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionOpenTable(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionPasteLayerStyle(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCopyLayerStyle(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddAmsLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddAfsLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddPointCloudLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddVectorTileLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddXyzLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddWmsLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddPgLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddRasterLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddOgrLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionNewVectorLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionDraw(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionShowBookmarks(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionNewBookmark(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionMapTips(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomActualSize(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomNext(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomLast(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomToSelected(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomToLayers(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomToLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomFullExtent(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionMeasureArea(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionMeasure(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionFeatureAction(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionIdentify(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSelectRadius(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSelectFreehand(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSelectPolygon(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSelectRectangle(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSelect(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomOut(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionZoomIn(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionPanToSelected(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionPan(self) -> Optional[QtWidgets.QAction]: - ... + pass def mapToolActionGroup(self) -> Optional[QtWidgets.QActionGroup]: - ... + pass def actionVertexToolActiveLayer(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionVertexTool(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionDeletePart(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionDeleteRing(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSimplifyFeature(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddPart(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddRing(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSplitParts(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSplitFeatures(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionMoveFeature(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionDeleteSelected(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionAddFeature(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionPasteFeatures(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCopyFeatures(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCutFeatures(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionExit(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionShowLayoutManager(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionCreatePrintLayout(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionProjectProperties(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSaveMapAsImage(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSaveProjectAs(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionSaveProject(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionOpenProject(self) -> Optional[QtWidgets.QAction]: - ... + pass def actionNewProject(self) -> Optional[QtWidgets.QAction]: - ... + pass def webToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def databaseToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def vectorToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def rasterToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def helpToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def pluginToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def selectionToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def attributesToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def shapeDigitizeToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def advancedDigitizeToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def digitizeToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def mapNavToolToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def openDataSourceManagerPage(self, pageName: Optional[str]) -> None: - ... + pass def dataSourceManagerToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def layerToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def fileToolBar(self) -> Optional[QtWidgets.QToolBar]: - ... + pass def helpMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def windowMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def firstRightStandardMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def webMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def vectorMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def databaseMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def rasterMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def pluginHelpMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def pluginMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def settingsMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def addLayerMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def newLayerMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def layerMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def viewMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def editMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def removeProjectExportAction(self, action: Optional[QtWidgets.QAction]) -> None: - ... + pass def addProjectExportAction(self, action: Optional[QtWidgets.QAction]) -> None: - ... + pass def removeProjectImportAction(self, action: Optional[QtWidgets.QAction]) -> None: - ... + pass def addProjectImportAction(self, action: Optional[QtWidgets.QAction]) -> None: - ... + pass def projectImportExportMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def projectMenu(self) -> Optional[QtWidgets.QMenu]: - ... + pass def cadDockWidget(self) -> Optional["QgsAdvancedDigitizingDockWidget"]: - ... + pass def defaultStyleSheetFont(self) -> QtGui.QFont: - ... + pass def defaultStyleSheetOptions(self) -> dict[str, Any]: - ... + pass def openLayoutDesigners(self) -> list["QgsLayoutDesignerInterface"]: - ... + pass def messageBar(self) -> Optional["QgsMessageBar"]: return self._messageBar @@ -1085,12 +1095,12 @@ def mainWindow(self) -> Optional[QtWidgets.QWidget]: return self._mainWindow def layerTreeCanvasBridge(self) -> Optional["QgsLayerTreeMapCanvasBridge"]: - ... + pass def activeDecorations(self) -> list[qgis_core.QgsMapDecoration]: - ... + pass - def mapCanvas(self) -> Optional["QgsMapCanvas"]: + def mapCanvas(self) -> "QgsMapCanvas": return self.canvas def activeLayer(self) -> Optional[qgis_core.QgsMapLayer]: @@ -1101,43 +1111,43 @@ def activeLayer(self) -> Optional[qgis_core.QgsMapLayer]: ) def editableLayers(self, modified: bool = ...) -> list[qgis_core.QgsMapLayer]: - ... + pass def iconSize(self, dockedToolbar: bool = ...) -> QtCore.QSize: - ... + pass def closeMapCanvas(self, name: Optional[str]) -> None: - ... + pass def createNewMapCanvas(self, name: Optional[str]) -> Optional["QgsMapCanvas"]: - ... + pass def mapCanvases(self) -> list["QgsMapCanvas"]: - ... + return [self.mapCanvas()] def removeCustomActionForLayerType( self, action: Optional[QtWidgets.QAction] ) -> bool: - ... + pass def addCustomActionForLayer( self, action: Optional[QtWidgets.QAction], layer: Optional[qgis_core.QgsMapLayer], ) -> None: - ... + pass def addCustomActionForLayerType( self, action: Optional[QtWidgets.QAction], menu: Optional[str], - type: qgis_core.Qgis.LayerType, + type: "qgis_core.Qgis.LayerType", allLayers: bool, ) -> None: - ... + pass def layerTreeView(self) -> Optional["QgsLayerTreeView"]: - ... + pass def pluginManagerInterface(self) -> Optional["QgsPluginManagerInterface"]: - ... + pass diff --git a/tests/test_pytest_qgis.py b/tests/test_pytest_qgis.py index 858606b..16bcb42 100644 --- a/tests/test_pytest_qgis.py +++ b/tests/test_pytest_qgis.py @@ -18,7 +18,6 @@ import pytest from qgis.core import QgsProcessing, QgsProject, QgsVectorLayer -from qgis.PyQt.QtWidgets import QToolBar from qgis.utils import iface from tests.utils import QGIS_VERSION @@ -45,12 +44,6 @@ def test_a_teardown(): """ -def test_add_layer(): - layer = QgsVectorLayer("Polygon", "dummy_polygon_layer", "memory") - QgsProject.instance().addMapLayer(layer) - assert set(QgsProject.instance().mapLayers().values()) == {layer} - - def test_qgis_new_project(qgis_new_project): assert QgsProject.instance().mapLayers() == {} @@ -87,32 +80,6 @@ def test_setup_qgis_iface(qgis_iface): assert iface == qgis_iface -def test_iface_active_layer(qgis_iface, layer_polygon, layer_points): - QgsProject.instance().addMapLayer(layer_polygon) - QgsProject.instance().addMapLayer(layer_points) - - assert qgis_iface.activeLayer() is None - qgis_iface.setActiveLayer(layer_polygon) - assert qgis_iface.activeLayer() == layer_polygon - qgis_iface.setActiveLayer(layer_points) - assert qgis_iface.activeLayer() == layer_points - - -def test_iface_toolbar_str(qgis_iface): - name = "test_bar" - toolbar: QToolBar = qgis_iface.addToolBar(name) - assert toolbar.windowTitle() == name - assert qgis_iface._toolbars == {name: toolbar} - - -def test_iface_toolbar_qtoolbar(qgis_iface): - name = "test_bar" - toolbar: QToolBar = QToolBar(name) - qgis_iface.addToolBar(toolbar) - assert toolbar.windowTitle() == name - assert qgis_iface._toolbars == {name: toolbar} - - def test_canvas_should_be_released(qgis_canvas, layer_polygon, layer_points): """ This test will not assert anything but calling zoom methods of qgis_canvas diff --git a/tests/test_qgis_interface.py b/tests/test_qgis_interface.py new file mode 100644 index 0000000..8864421 --- /dev/null +++ b/tests/test_qgis_interface.py @@ -0,0 +1,70 @@ +from pathlib import Path + +import pytest +from qgis.core import QgsProject, QgsVectorLayer +from qgis.gui import QgisInterface +from qgis.PyQt.QtWidgets import QToolBar + +RASTER_PATH = Path(Path(__file__).parent, "data", "small_raster.tif") + + +@pytest.fixture(autouse=True) +def _setup(qgis_new_project: None) -> None: + pass + + +def test_add_vector_layer(): + layer = QgsVectorLayer("Polygon", "dummy_polygon_layer", "memory") + assert QgsProject.instance().addMapLayer(layer) + assert set(QgsProject.instance().mapLayers().values()) == {layer} + + +def test_add_vector_layer_via_iface(qgis_iface: "QgisInterface"): + layer = qgis_iface.addVectorLayer("Polygon", "dummy_polygon_layer", "memory") + assert layer.isValid() + assert QgsProject.instance().addMapLayer(layer) + assert set(QgsProject.instance().mapLayers().values()) == {layer} + + +def test_add_raster_layer_via_iface(qgis_iface: "QgisInterface"): + layer = qgis_iface.addRasterLayer( + str(RASTER_PATH), + "Raster", + ) + assert QgsProject.instance().addMapLayer(layer) + assert set(QgsProject.instance().mapLayers().values()) == {layer} + + +def test_iface_active_layer( + qgis_iface: "QgisInterface", + layer_polygon: "QgsVectorLayer", + layer_points: "QgsVectorLayer", +): + QgsProject.instance().addMapLayer(layer_polygon) + QgsProject.instance().addMapLayer(layer_points) + + assert qgis_iface.activeLayer() is None + qgis_iface.setActiveLayer(layer_polygon) + assert qgis_iface.activeLayer() == layer_polygon + qgis_iface.setActiveLayer(layer_points) + assert qgis_iface.activeLayer() == layer_points + + +def test_iface_toolbar_str(qgis_iface: "QgisInterface"): + name = "test_bar" + toolbar: QToolBar = qgis_iface.addToolBar(name) + assert toolbar.windowTitle() == name + assert qgis_iface._toolbars == {name: toolbar} + + +def test_iface_toolbar_qtoolbar(qgis_iface: "QgisInterface"): + name = "test_bar" + toolbar: QToolBar = QToolBar(name) + qgis_iface.addToolBar(toolbar) + assert toolbar.windowTitle() == name + assert qgis_iface._toolbars == {name: toolbar} + + +def test_iface_has_all_qgis_interface_methods(qgis_iface: "QgisInterface"): + for method_name in dir(QgisInterface): + assert hasattr(qgis_iface, method_name)