mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -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.qgssettings import _qgssettings_enum_value, _qgssettings_set_enum_value, _qgssettings_flag_value
|
||||||
from .additions.qgstaskwrapper import QgsTaskWrapper
|
from .additions.qgstaskwrapper import QgsTaskWrapper
|
||||||
from .additions.readwritecontextentercategory import ReadWriteContextEnterCategory
|
from .additions.readwritecontextentercategory import ReadWriteContextEnterCategory
|
||||||
|
from .additions.validitycheck import check
|
||||||
|
|
||||||
# Injections into classes
|
# Injections into classes
|
||||||
QgsFeature.__geo_interface__ = property(mapping_feature)
|
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,
|
QgsValidityCheckRegistry,
|
||||||
QgsValidityCheckResult,
|
QgsValidityCheckResult,
|
||||||
QgsValidityCheckContext,
|
QgsValidityCheckContext,
|
||||||
QgsFeedback)
|
QgsFeedback,
|
||||||
|
check)
|
||||||
from qgis.testing import start_app, unittest
|
from qgis.testing import start_app, unittest
|
||||||
|
|
||||||
app = start_app()
|
app = start_app()
|
||||||
@ -53,12 +54,37 @@ class TestContext(QgsValidityCheckContext):
|
|||||||
return 0
|
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):
|
class TestQgsValidityChecks(unittest.TestCase):
|
||||||
|
|
||||||
def testAppRegistry(self):
|
def testAppRegistry(self):
|
||||||
# ensure there is an application instance
|
# ensure there is an application instance
|
||||||
self.assertIsNotNone(QgsApplication.validityCheckRegistry())
|
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):
|
def testRegistry(self):
|
||||||
registry = QgsValidityCheckRegistry()
|
registry = QgsValidityCheckRegistry()
|
||||||
self.assertFalse(registry.checks())
|
self.assertFalse(registry.checks())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user