mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-12 00:06:43 -04:00
[api][needs-docs] Allow registering PyQGIS using a nice decorator syntax
This allows nice and simple, elegant construction of checks for Python. To use, Python based checks should use the decorator syntax: from qgis.core import check @check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck) def my_layout_check(context, feedback): results = ... return results Or, a more complete example. This one throws a warning when attempting to export a layout with a map item set to the Web Mercator projection: @check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck) def layout_map_crs_choice_check(context, feedback): layout = context.layout results = [] for i in layout.items(): if isinstance(i, QgsLayoutItemMap) and i.crs().authid() == 'EPSG:3857': res = QgsValidityCheckResult() res.type = QgsValidityCheckResult.Warning res.title='Map projection is misleading' res.detailedDescription='The projection for the map item {} is set to <i>Web Mercator (EPSG:3857)</i> which misrepresents areas and shapes. Consider using an appropriate local projection instead.'.format(i.displayName()) results.append(res) return results
This commit is contained in:
parent
fd001bbd4d
commit
fdfe0cee23
@ -37,6 +37,7 @@ from .additions.qgsgeometry import _geometryNonZero, mapping_geometry
|
||||
from .additions.qgssettings import _qgssettings_enum_value, _qgssettings_set_enum_value, _qgssettings_flag_value
|
||||
from .additions.qgstaskwrapper import QgsTaskWrapper
|
||||
from .additions.readwritecontextentercategory import ReadWriteContextEnterCategory
|
||||
from .additions.validitycheck import check
|
||||
|
||||
# Injections into classes
|
||||
QgsFeature.__geo_interface__ = property(mapping_feature)
|
||||
|
95
python/core/additions/validitycheck.py
Normal file
95
python/core/additions/validitycheck.py
Normal file
@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
***************************************************************************
|
||||
validitycheck.py
|
||||
---------------------
|
||||
Date : January 2019
|
||||
Copyright : (C) 2019 by Nyall Dawson
|
||||
Email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************
|
||||
"""
|
||||
from qgis._core import (
|
||||
QgsAbstractValidityCheck,
|
||||
QgsApplication)
|
||||
|
||||
|
||||
class CheckFactory:
|
||||
"""
|
||||
Constructs QgsAbstractValidityChecks using a decorator.
|
||||
|
||||
To use, Python based checks should use the decorator syntax:
|
||||
|
||||
.. highlight:: python
|
||||
.. code-block:: python
|
||||
@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
|
||||
def my_layout_check(context, feedback):
|
||||
results = ...
|
||||
return results
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# unfortunately /Transfer/ annotation isn't working correct on validityCheckRegistry().addCheck(),
|
||||
# so we manually need to store a reference to all checks we register
|
||||
self.checks = []
|
||||
|
||||
def register(self, type, *args, **kwargs):
|
||||
"""
|
||||
Implements a decorator for registering Python based checks.
|
||||
|
||||
:param type: check type, e.g. QgsAbstractValidityCheck.TypeLayoutCheck
|
||||
"""
|
||||
|
||||
def dec(f):
|
||||
check = CheckWrapper(check_type=type, check_func=f)
|
||||
self.checks.append(check)
|
||||
QgsApplication.validityCheckRegistry().addCheck(check)
|
||||
|
||||
return dec
|
||||
|
||||
|
||||
class CheckWrapper(QgsAbstractValidityCheck):
|
||||
"""
|
||||
Wrapper object used to create new validity checks from @check.
|
||||
"""
|
||||
|
||||
def __init__(self, check_type, check_func):
|
||||
"""
|
||||
Initializer for CheckWrapper.
|
||||
|
||||
:param check_type: check type, e.g. QgsAbstractValidityCheck.TypeLayoutCheck
|
||||
:param check_func: test function, should return a list of QgsValidityCheckResult results
|
||||
"""
|
||||
super().__init__()
|
||||
self._check_type = check_type
|
||||
self._results = []
|
||||
self._check_func = check_func
|
||||
|
||||
def create(self):
|
||||
return CheckWrapper(check_type=self._check_type, check_func=self._check_func)
|
||||
|
||||
def id(self):
|
||||
return self._check_func.__name__
|
||||
|
||||
def checkType(self):
|
||||
return self._check_type
|
||||
|
||||
def prepareCheck(self, context, feedback):
|
||||
self._results = self._check_func(context, feedback)
|
||||
if self._results is None:
|
||||
self._results = []
|
||||
return True
|
||||
|
||||
def runCheck(self, context, feedback):
|
||||
return self._results
|
||||
|
||||
|
||||
check = CheckFactory()
|
@ -19,7 +19,8 @@ from qgis.core import (QgsApplication,
|
||||
QgsValidityCheckRegistry,
|
||||
QgsValidityCheckResult,
|
||||
QgsValidityCheckContext,
|
||||
QgsFeedback)
|
||||
QgsFeedback,
|
||||
check)
|
||||
from qgis.testing import start_app, unittest
|
||||
|
||||
app = start_app()
|
||||
@ -53,12 +54,37 @@ class TestContext(QgsValidityCheckContext):
|
||||
return 0
|
||||
|
||||
|
||||
# register some checks using the decorator syntax
|
||||
@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
|
||||
def my_check(context, feedback):
|
||||
assert context
|
||||
|
||||
|
||||
@check.register(type=QgsAbstractValidityCheck.TypeLayoutCheck)
|
||||
def my_check2(context, feedback):
|
||||
res = QgsValidityCheckResult()
|
||||
res.type = QgsValidityCheckResult.Warning
|
||||
res.title = 'test'
|
||||
res.detailedDescription = 'blah blah'
|
||||
return [res]
|
||||
|
||||
|
||||
class TestQgsValidityChecks(unittest.TestCase):
|
||||
|
||||
def testAppRegistry(self):
|
||||
# ensure there is an application instance
|
||||
self.assertIsNotNone(QgsApplication.validityCheckRegistry())
|
||||
|
||||
def testDecorator(self):
|
||||
# test that checks registered using the decorator have worked
|
||||
self.assertEqual(len(QgsApplication.validityCheckRegistry().checks()), 2)
|
||||
|
||||
context = TestContext()
|
||||
feedback = QgsFeedback()
|
||||
res = QgsApplication.validityCheckRegistry().runChecks(QgsAbstractValidityCheck.TypeLayoutCheck, context, feedback)
|
||||
self.assertEqual(len(res), 1)
|
||||
self.assertEqual(res[0].title, 'test')
|
||||
|
||||
def testRegistry(self):
|
||||
registry = QgsValidityCheckRegistry()
|
||||
self.assertFalse(registry.checks())
|
||||
|
Loading…
x
Reference in New Issue
Block a user